0

This example is about having a request from a customer where the seller can choose to make an offer to the customer.

The request is stored in a class named 'Request' and the offer is stored in the class 'Offer'.

The flow is:

  1. The seller picks up a request from the request-list and is redirected to the Request.show-form.

  2. Here he can choose, by a link, to create an offer using the data in this request.

  3. Now the seller is redirected to the Offer.Create-form which is filled with data from the request.

  4. The seller now can add and or change data and the either confirm or cancel this offer.

That's it.

My idea is that the Request-controller, after receiving the action, will take the ID of the request then calling a service, Offer_service, which in turn reads the request using the ID and then creates a new Offer-object. The service continues with filling this object with data from the request-object and then calling the Offer-controller to open up the create-form to let the seller complete the offer.

I want to know if I'm on the right way or if I'm missing something?

Of course, this is simple for you, experienced people but for me... I'm new and feel like beeing on deep water sometimes. I would appreciate every type of advices, tips etc. that can lead me forward.

Amendment.. You see, we want to keep request and offer independent of each other and if the seller wants to change some of the values from the request he will do that to the offer only. The values in the request should be unchanged. And more, the id of the offer should be stored in the request so you can jump directly from a request-form to the offer if wanted. And vice-versa an id to the request should be stored in the offer to make it possible to go back to request. But those links(id:s) should only be set if the offer is saved (confirmed). It is also a possibility that more processing should be done to the request-data before it is stored in the offer. An offer may also be constructed without a request behind and then there is no connection to the request. That's why I think a service should be good to keep request and offer independent of each other.

larand
  • 773
  • 1
  • 9
  • 26

1 Answers1

0

Think you are over complicating things. In short when you have the id of the request. for offer object that is all it needs.

so here goes:

<!-- this is in your gsp form that will be sending to request controller -maybe possibly it shold OfferController -->
<g:hiddenField name="userRequest.id" value="${instance.id}"/>

In that controller

def MyController {

   def actionOffer(OfferBean bean) {
        bean.formatBean()
        if (!bean.hasErrors()) {
            //do SOmething
            render view:'myView', model:[instance:bean]
            return
        } 

        render view:'failedView', model:[instance:bean]
   }
 }

in src/main/groovy/package/OfferBean.groovy

class OfferBean implements Validateable {
   // this is your actual request class
   UserRequestBean userRequestBean
   UserRequest userRequest

   static constraints = {
     request(nullable:false) //, validator:checkRequest)
   }

   def formatBean() {
    UserRequestBean userRequestBean = new UserRequestBean()
    userRequestBean.formatBean(request)
   }

  //You actually do not need this at all. 

  static def checkRequest = { val, obj, errors ->
        if (!Request.get(obj.request.id)) {
            errors.rejectValue('message','invalid.requestId',[val] as Object[],'')
        }
    }
}

Basically all you need is the userRequest.id as a hidden params passed to the validation class of OfferBean with the constraints set as false this means if the userRequest.id did not magically bind with UserRequest domain class it will invalidate and fall outside of the do Something block which has a return telling it all was okay and processed within that block

Most importantly once the binding has happened i.e. no issues you auto magically then can access all the request elements from within the bean within actionOffer gsp

Do you see what I mean by complicating when comparing above to what you wrote ?

updated controller to show how you pass bean back to view. in the acionOffer myView gsp if you now refer to ${instance.userRequestBean.something} this will map and return back the something object from within request. (no need to build anything up) once you have the id

So after reading your comments what you then need is another bean for the request, when a request object is saved in the bean like below you already have the bean. Anyhow assuming you

in src/main/groovy/package/UserRequestBean.groovy

 class UserRequestBean implements Validateable {
   def id 
   String name
   //mapped like your UserRequestBean domain class 
   //meaning it contains all elements

   //Now a function to map in actual user request
   //into this bean
   protected def formatBean(UserRequest ur) {
    this.id=ur.id
    this.name=ur.name
    //and so on

    return this
   }

}

reveiew the updated code, I have added a new formatBean function which called in main class that then binds a new userRequestBean that now contains all the elements of your actual userRequest domain class - you now can access those on the new form as userRequestBean.

I still don't think you need all this complexity.

You say user then wants to update the request so what as it was originally you get ${instance.userRequest} entire object you simply repeat the form with the existing values, upon save you then have to capture them again so you re-apply existing code that saved original object to these params,

anyhow i have shown you a far more complex way of binding a real domain class to a transient object (non database) when you are happy you can

then save those values back over the main class you could introduce


def loadValues() { 
  Map values=[:]
  //mapping all domain class objects back form bean 
  //required ones
  values.with { 
    id=this.id
    name=this.name
   }
  return values
}

then your object.properties=bean.loadValues()

V H
  • 8,382
  • 2
  • 28
  • 48
  • Hmm.. I'm not quite sure if I understand you 100%. As I understand is that I should only store the reference to the request object, i.e. field request, in the offer object and then display the columns from request directly in offers create-view? Check my amendment above. – larand Feb 25 '17 at 13:43
  • I expanded the answer it is up to you to get your head around and take what you want out of that – V H Feb 25 '17 at 15:02
  • So in short on primary page collecting request the params would be `${instance.whatever}` on 2nd offerRequest gsp page the object for request is already mapped to domain class. If you need to edit them the params of OfferBean are `` and the values if you need to edit for old form is when posted to that bean it would bind with each object and you need to be careful real objects can save without save. On 2nd page you have id of 1st you send that in too – V H Feb 25 '17 at 15:36
  • and update primary class rather than save again - since you now have id – V H Feb 25 '17 at 15:36
  • You wrote something about "the user want's to change something in the request". That's not what I meant, I meant that the seller wants to change some values retrieved from the request in the offer. The offer can be changed but the request must not be changed if not requested by the cusomer. If a customer requests a qty of say 10 packages but the seller can't offer less than 12packages then he will offer 12 packages but the request must still say 10 packages. A customer can make a request by email, phone or by creating a request using the create-request-form. – larand Feb 25 '17 at 17:11
  • If the request is entered by email or phone then the seller must create the request. The meaning is to maintain a list of customer requests so the seller(s) can check this list against a list of available products and then make offers out of that. The requests is never deleted or changed they are stored for future follow up. – larand Feb 25 '17 at 17:17
  • so what is the problem ? you are grabbing the request object then making a new object out it ? you already have it bound as explained so far you then put the values of that into a new form field which has the new form input name and old binded value from request – V H Feb 25 '17 at 17:24
  • I think a lot of recent stuff i have come across isn't explained well and hence ends up getting a twisted answer. It is always best to clearly outline and in least amount of words a problem. Anyhow I have created something to explain above https://github.com/vahidhedayati/testBeanBinding feel free to refer it as reference. In your case you want an object to then change it to somthing else in another object ? it is already starting to twist itself. in given example the child has a copy of original and new - I have provided a checksum example - you need to compare old/new values if not changed – V H Feb 25 '17 at 17:48
  • to create a new parent object in child object otherwise it can just use the existing parent - I can't really hold hands beyond this point – V H Feb 25 '17 at 17:48
  • Ok, I've checked your testproject and verified that I did understand what you meant. And of course I could use the object instead of an id of the project but I think I have to keep columns of offer separate, imagine if the seller want's to create an offer without having a request. Then he has to create a request anyway. Either by entering the request-create-form first or else I need to create a create-form that creates both a request and an offer-object. This is of course possible but I don't feel too comfortable with it. I'm not giving up your idea - it would simplify coding. – larand Feb 26 '17 at 09:48
  • But it won't be so nice when you list your request's when these requests show up. I have to add a field that identifies these requests so they can be filtered out. – larand Feb 26 '17 at 09:51
  • Offer should be offer and request should be request. My method tries to separate the objects. If offer requires a request to be created then so be it. If it modifies request a new request is made and has two object references. The difference is if it has second object binding then that is most latest if not (no changes to original) or (an offer that had no request) then it has no 2nd so by default use the 1st object reference. Your original idea suggested having request that has fields and offer that also then has those fields and copies stuff over and over - duplicated data large db future .. – V H Feb 26 '17 at 10:16
  • Also it is rather unclear I mean this morphing of request/offer. If both same fields then maybe Offer should extend Request and have no additional fields besides nullable originalRequest object. If new then will be a new offer object if a rewrite will be a new offer object that ties in originalRequest. Take a look at the queuekit plugin domain classes they extend and tweak behaviour slightly then when queried in service they are bound to their types – V H Feb 26 '17 at 10:55