On Tue, Mar 30, 2010 at 8:10 PM, Richtermeister <nex...@gmail.com> wrote:
> Hey Tom,
>
> any time.
>
> The reason to keep orders and the cart separate is an issue of
> separation of concerns, where we're trying to avoid having classes do
> too many things (for all the obvious reasons of maintainability,
> easier unit testing and future flexibility).
>
> In our system orders are considered part of the persistence layer
> (simple propel objects really), so they fundamentally work like data
> storage and need to be viewable in different applications (admin area,
> customer service, automated export). This makes the order more of a
> historic document than an active element, and we feel this describes
> better what it really is.
>
> The cart on the other hand is an object that assembles an order, (an
> actor), and for that it needs to interact with lots of other objects,
> such as the current user (logged in, or guest?), shipping and tax
> services, promotions, etc. As you can see, that becomes quite a lot of
> code to drag around if you were to make this part of the order, and
> none of that is needed any more after an order is placed and post-
> checkout life-cycle begins. Also, this would potentially tie orders to
> one specific application (at least our cart is aware of the user,
> although I guess you could handle that differently).
>
> So, like Antoine said, it's easier to have createOrder() and
> loadOrder($order) methods on the cart, and otherwise keep them
> separate.
> Does that make sense?

But what if you want to change the shipping or add an item after the
customer has placed an order? The order is still acting like a cart
even though it is now technically an order. I took over a Codeigniter
project that has a separate cart and order and there is a lot of
duplication of code. For example the ability to apply a promotion to
both cart (before checkout) and an order (after checkout).  Granted,
the project is quite poorly written but still I'm thinking I can avoid
this by taking an order from cart to delivery.

>
> As for the promotion classes, in our system there are model classes
> which represent a "PromotionEvent", and store date and configuration
> of a promotion. At runtime, this model class is used to create and
> configure a more lightweight promotion class which can only apply
> itself to the cart. Same for criteria by the way, one class for
> storage, one for runtime. So, for each promotion at runtime you have a
> minimum of 4 classes going to work, plus the cart. Plus whatever else
> they need to do their job.

I was also thinking of having a Promotion table which would hold the
config info. Then I would apply the promo to the order with the
PromoManager. So you'd pass the Promo and Order to the PromoManager.
Then depending on the promo type, the Promo manger loads the relevant
sub class e.g. PromoManagerGiftWithPurchase. With our current project
you can only have one promo code, but I guess using weights would be a
good way to manage multiple promos.

In the action:

$promoManager = new PromoManager();
$promotion        = Doctrine::getTable('Promotion')->getByCode($code);

$order = $promoManager->applyPromo($order, $promotion);

then in the PromoManager:

protected function getPromoClass($promotion)
{
  $promoClassName = $promotion->class_name;
   ...
   $this->promoClass = new $promoClassName();
}

Is this similar to what you're doing? or not at all?

>
> The reason for this separation is the same as above. Basically, I look
> at propel classes as storage, and I like to code my systems to rely as
> little as possible on one particular storage medium. For example, if I
> were to switch to Doctrine (no intentions), I would only have to swap
> out the "dumb" classes without touching the ones containing the logic.
> Oh, and there's another reason.. for performance reason we cache
> promotions between certain checkout steps, and it's easy to serialize
> simple objects, while serializing propel objects is both tricky and
> introduces potential for stale data.
>
> That help?
> Daniel
>
>
>
>
>
>
> On Mar 30, 6:09 am, Tom Haskins-Vaughan <t...@templestreetmedia.com>
> wrote:
>> Thanks, guys! That's a great help. I will most probably take you up on
>> your offer of help! :)  In the meantime, I have a couple of follow on
>> questions:
>>
>> 1. What do you see the benefits of having a separate cart and order objects?
>>
>> 2. The Promotion classes were the logic takes place, are they also
>> model classes or are they separate classes?
>>
>> Thanks again.
>>
>> Tom
>>
>> On Tue, Mar 30, 2010 at 2:00 AM, Richtermeister <nex...@gmail.com> wrote:
>> > Hey Tom,
>>
>> > I wrote the ecommerce part ofwww.skinmedica.com, which uses a quite
>> > complex promotions setup and took some iterations to get it right. I'd
>> > be happy to help.
>>
>> > Our cart works similar to what Antoine said, where the shopping cart
>> > is distinct from the final order, and mostly responsible for keeping
>> > track of what's in it for calculating prices (shipping, tax, total,
>> > etc. - the cart is actually composed of different independent service
>> > classes to look up shipping, & tax via webservices). Generally we try
>> > to keep the cart very limited in what it knows about the rest of the
>> > system.
>>
>> > The way the promotions work is that they're being applied to the cart
>> > without the cart knowing much about what is happening. A promotion is
>> > basically handed the entire cart and it gets to decide whether it
>> > applies. It does that by using a separate class, a promotion
>> > criterion, which depending on its type can apply different logic to
>> > trigger whether it applies. For example, we have promotion criteria
>> > that trigger based on:
>> > - a certain cart subtotal
>> > - whether a certain product is in the cart
>> > - whether the customer is new
>> > - etc.
>> > Those are all different classes, extending a BasePromotionCriterion,
>> > that are further customizable via parameters from an admin area.
>>
>> > When the promotion applies, it gets to make changes to the cart. Those
>> > changes, in turn, depend on the type of the promotion class.
>> > We have promotions that:
>> > - apply a cart discount
>> > - apply a product discount
>> > - add a free product
>> > - make shipping free of charge
>> > - etc.
>>
>> > By combining criterion classes with promotions classes, and passing a
>> > few parameters along, you can create virtually any combination of
>> > promotions, and when you find limitations, you can simply add more
>> > classes. Plus, this is fairly easy to administer.
>>
>> > The hardest part is issues like precedence and mutual exclusivity. For
>> > example, if a promotion applies a cart discount at a certain subtotal,
>> > then that in turn can lower the subtotal. So, the system needs to be
>> > smart enough not to remove the promotion again. Or, there are
>> > szenarios where 2 free shipping promotions are applicable, but the
>> > system should only apply one (usually the cheaper one, but that can
>> > vary).
>> > So, basically we apply weights to classes to figure out in which order
>> > the promotions apply, and there is an override parameter that enables
>> > each promotion to override others, for some manual finetuning.
>> > Sorting that all out is a matter of a series of interesting loops with
>> > callbacks that cost me a few sleepless nights :)
>>
>> > Does that help? Let me know if you have any specific questions and I'd
>> > be happy to help more.
>> > Daniel
>>
>> > On Mar 29, 5:56 pm, Tom Haskins-Vaughan <t...@templestreetmedia.com>
>> > wrote:
>> >> (sf1.4/Doctrine)
>>
>> >> Hi all,
>>
>> >> Let's say I'm developing an ecommerce solution. I have the following 
>> >> models:
>>
>> >> Order - takes a shopping cart all the way through to an actual order.
>>
>> >> OrderItem - link between the Order and one or more Products
>>
>> >> Product - a catalogue of products
>>
>> >> Promotion - e.g., buy one get one free, or 10% off item, buy these
>> >> both for $10, etc
>>
>> >> The part I'm interested in is the promotions. I *could* do the logic
>> >> in the Order model like so:
>>
>> >> $order = new Order();
>> >> ...
>> >> $order->applyPromotion($promotion);
>>
>> >> But there is likely to be quite a lot of logic, depending on what kind
>> >> of promotion it is (adding OrderItems, discounting Orders, etc), so my
>> >> instinct was to create a PromotionManager class so for example:
>>
>> >> $promoManager = new PromotionManager();
>> >> $promoManager->appyPromotion($promotion, $order);
>>
>> >> Is this a better way to go, or am I causing myself needless abstraction?
>>
>> >> I know there's more than one way to skin a cat, but I'm trying hard to
>> >> get to grips with the best way.
>>
>> >> Anyway, thanks in advance.
>>
>> >> Tom
>>
>> > --
>> > If you want to report a vulnerability issue on symfony, please send it to 
>> > security at symfony-project.com
>>
>> > You received this message because you are subscribed to the Google
>> > Groups "symfony users" group.
>> > To post to this group, send email to symfony-users@googlegroups.com
>> > To unsubscribe from this group, send email to
>> > symfony-users+unsubscr...@googlegroups.com
>> > For more options, visit this group at
>> >http://groups.google.com/group/symfony-users?hl=en
>>
>> > To unsubscribe from this group, send email to 
>> > symfony-users+unsubscribegooglegroups.com or reply to this email with the 
>> > words "REMOVE ME" as the subject.
>
> --
> If you want to report a vulnerability issue on symfony, please send it to 
> security at symfony-project.com
>
> You received this message because you are subscribed to the Google
> Groups "symfony users" group.
> To post to this group, send email to symfony-users@googlegroups.com
> To unsubscribe from this group, send email to
> symfony-users+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/symfony-users?hl=en
>

-- 
If you want to report a vulnerability issue on symfony, please send it to 
security at symfony-project.com

You received this message because you are subscribed to the Google
Groups "symfony users" group.
To post to this group, send email to symfony-users@googlegroups.com
To unsubscribe from this group, send email to
symfony-users+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/symfony-users?hl=en

Reply via email to