-
Notifications
You must be signed in to change notification settings - Fork 0
/
ic_ecommerce.sdf
1674 lines (1205 loc) · 58.1 KB
/
ic_ecommerce.sdf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
!init OPT_LOOK="icdevgroup"; OPT_STYLE="manual"
# $Id: ic_ecommerce.sdf,v 1.25 2004-05-05 15:22:29 jon Exp $
!define DOC_NAME "Interchange Ecommerce Functions"
!define DOC_TYPE ""
!define DOC_CODE "ic_ecommerce"
!define DOC_VERSION substr('$Revision: 1.25 $',11, -2)
!define DOC_STATUS "Draft"
!define DOC_PROJECT "Interchange"
!define DOC_URL "http://www.icdevgroup.org/doc/ic_ecommerce.html"
!build_title
H1: THE ORDER PROCESS
Interchange has a completely flexible order basket and checkout
scheme. The C<foundation> demo presents a common use of this process,
in the directory pages/ord -- the files are:
> basket.html The order basket displayed by default
> checkout.html The form where the customer enters their billing
> and shipping info
... and in the directory etc:
> receipt.html The receipt displayed to the customer
> report The order report mailed to you
> mail_receipt The customer's email copy (if requested)
It is not strictly necessary to display an order basket when
an item is ordered. If you specify a different page to be
displayed that is fine, but most customers will be confused if
you don't give them an indication that the order operation has
succeeded.
Any order basket is an HTML C<FORM>. It will have a number of
variables on it. At the minimum it must have an C<[item-list]> to
loop through the items, and the C<quantity> of each item must be
set in some place on that form. Any valid Interchange tags may be
used on the page, and you may use multiple item lists if necessary.
H2: How to order an item
Interchange can either use a form-based order or a link-based order to
place an item in the shopping cart. The link-based order uses the
special C<[order item-code]> tag:
=over 4
=item [order code]
named attributes:
> [order code="sku" quantity="n"* href="page"* cart="cartname"* base="table"*]
> * = optional parameters
Expands into a hypertext link which will include the specified
code in the list of products to order and display the order page. B<code>
should be a product SKU listed in one of the "products" tables, and is the
only required parameter. B<quantity> may be specified if more than one
(the default) of the item should be
placed in the cart. B<href> allows some page other than the default order
page to be displayed once the item has been added to the cart. B<cart>
selects the shopping cart the item will be placed in. The optional argument
B<base> constrains
the order to a particular products file -- if not specified, all tables
defined as products files will be searched in sequence for the item.
N:
N: Example:
> Order a [order TK112]Toaster</a> today.
Note that this is the same as:
> Order a [page order TK112]Toaster</A> today.
You can change frames for the order with:
> Order a <A HREF="[area order TK112]" TARGET=newframe>Toaster</A> today.
=item [/order]
Expands into </a>. May be used to give the order tag the appearance
of being a container tag, but neither necessary nor recommended.
=back
To order with a form, you set the form variable C<mv_order_item> to
the item-code/SKU and use the C<refresh> action:
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME="mv_todo" VALUE="refresh">
> <INPUT TYPE=hidden NAME="mv_order_item" VALUE="TK112">
>
> Order <INPUT NAME="mv_order_quantity" SIZE=3 VALUE=1> toaster
>
> <INPUT TYPE=submit VALUE="Order!">
> </FORM>
You may batch select whole groups of items:
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME="mv_todo" VALUE="refresh">
>
> <INPUT TYPE=hidden NAME="mv_order_item" VALUE="TK112">
> <INPUT NAME="mv_order_quantity" SIZE=3> Standard Toaster
>
> <INPUT TYPE=hidden NAME="mv_order_item" VALUE="TK200">
> <INPUT NAME="mv_order_quantity" SIZE=3> Super Toaster
>
> <INPUT TYPE=submit VALUE="Order!">
> </FORM>
Items that have a quantity of zero (or blank) will be skipped, and only
items with a positive quantity will be placed in the basket.
You may also specify attributes like size or color at time of order (see
I<How to set up an order button>).
H2: How to set up an order link
On a product display page, use:
> [order 00-0011]Order the Mona Lisa</a>
If coming from a search results or on-the-fly page, you may use the generated
C<[item-code]> thusly:
> [order [item-code]]Order [item-field name]</a>
Bear in mind that if you have not reached the page via a search or
on-the-fly operation, C<[item-code]> means nothing and will cause an error.
H2: How to set up an order button
Interchange can order via form submission as well. This allows you
to order a product (or group of products) via a form button. In its
simplest form, it is:
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
> <INPUT TYPE=submit VALUE="Order the Mona Lisa">
> </FORM>
The default quantity is one. An initial quantity may be set by the user
by adding an mv_order_quantity variable:
> Number to order:<INPUT TYPE=text NAME=mv_order_quantity VALUE="1">
You can order multiple items by stacking the variables:
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
> <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
> </FORM>
Initial size or color may be set as well, provided I<UseModifier> is
set up properly:
> <INPUT TYPE=hidden NAME=mv_order_size VALUE="L">
If the order is coming from a generated flypage, loop list, or search
results page, you can get a canned select box from the
C<[item-accessories size]> or C<[item-accessories size]> tag. See
I<Item Attributes>.
H2: How to set up an on-the-fly item
If you enable the catalog directive I<OnFly>, setting it to the
name of a subroutine (or possibly a UserTag) that can handle its calls, then
Interchange will add items to the basket that are not in the product
database. Interchange supplies an internal C<onfly> subroutine, which
will work according to the examples given below.
In C<catalog.cfg>:
> OnFly onfly
If your item code is not to be named C<mv_order_item> then you
must perform a rename in the C<Autoload> routine.
A basic link can be generated like:
> <a href="[area form="
> mv_todo=refresh
> mv_order_item=000101
> mv_order_fly=description=An on-the-fly item|price=100.01
> "]">Order item 000101</a>
The form parameter value C<mv_order_fly> can contain any number of fields
which will set corresponding parameters in the item attributes. The fields
are separated by the pipe (C<|>) character and contain value-parameter
pairs separated by an = sign. (These are URL-encoded by the C<[area ...]> or
C<[page ...]> tag, of course.) You can set a size, color, or any other parameter.
The special attribute C<mv_price> can be used in conjunction with the
C<CommonAdjust> atom C<$> to set the price for checkout and display.
The C<[item-list]> sub-tag C<[item-description]>, when used with an
item-list, will use the item attribute C<description> to display in the
basket. Note that C<[item-field description]> or C<[item-data products description]>
will NOT work, as both of these tags reference an actual field value for
a record in the products table - not applicable for on-the-fly items.
Similarly, an attempt to generate a flypage for an on-the-fly item
(C<[page 000101]>, for example) will fail, resulting in the display of
the SpecialPage B<missing>.
If you wish to set up a UserTag to process on-the-fly items, it should
accept a call of
> usertag(mv_item_code, mv_item_quantity, mv_order_fly)
The C<mv_item_code> and C<mv_order_fly> parameters are required to trigger
Interchange's C<add_item> routine (along with mv_todo=refresh to set the action).
The item will always act as if C<SeparateItems> or C<mv_separate_items> is
set.
Multiple items can be ordered at once by stacking the variables. If there
is only one C<mv_order_item> instance, however, you can stack the C<mv_order_fly>
variable so that all are concatenated together as with the C<|> symbol. So
the above example could be done as:
> [area form="
> mv_todo=refresh
> mv_order_item=000101
> mv_order_fly=description=An on-the-fly item
> mv_order_fly=price=100.00
> "]
Multiple items would need multiple instances of C<mv_order_item> with
a corresponding C<mv_order_fly> for each C<mv_order_item>. You can
order both C<000101> and C<000101> as follows:
> [area form="
> mv_todo=refresh
>
> mv_order_item=000101
> mv_order_fly=description=An on-the-fly item|price=100.00
>
> mv_order_item=000102
> mv_order_fly=description=Another on-the-fly item|price=200.00
> "]
The following two forms correspond to the above two examples, in order,
with the slight refinement of adding a quantity:
> <FORM ACTION="[area process]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1">
> <INPUT TYPE=hidden NAME=mv_order_fly
> VALUE="description=An on-the-fly item|price=100.00">
> <INPUT TYPE=submit VALUE="Order button">
> </FORM>
>
> <FORM ACTION="[area process]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
> <INPUT TYPE=hidden NAME=mv_order_fly
> VALUE="description=An on-the-fly item|price=100.00">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000102">
> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
> <INPUT TYPE=hidden NAME=mv_order_fly
> VALUE="description=Another on-the-fly item|price=200.00">
> <INPUT TYPE=submit VALUE="Order two different with a button">
> </FORM>
H2: Order Groups
Interchange allows you to group items together, making a master item
and sub-items. This can be used to delete accessories or options when
the master item is deleted. In its simplest form, you order just one
master item and all subsequent items are sub-items.
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
> <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
> </FORM>
If you wish to stack more than one master item, then you must define
mv_order_group for B<all> items, with either a 1 value (master) or 0 value
(sub-item). A master owns all subsequent sub-items until the next master
is defined.
> <FORM ACTION="[process-target]" METHOD=POST>
> <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
> <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="19-202">
> <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
> <INPUT TYPE=hidden NAME=mv_order_item VALUE="99-102">
> <INPUT TYPE=submit VALUE="Order items">
> </FORM>
When the master item C<00-0011> is deleted from the basket,
C<00-0011a> will be deleted as well. And when 19-202 is deleted,
then 99-102 will be deleted from the basket.
\NOTE: Use of checkboxes for this type of thing can be hazardous, as they
do not pass a value when unchecked. It is preferable to use radio groups
or select/drop-down widgets. If you must use checkboxes, be sure to
explicitly clear C<mv_order_group> and C<mv_order_item> somewhere on the
page which contains the form:
> [value name=mv_order_group set='']
> [value name=mv_order_item set='']
The attributes C<mv_mi> and C<mv_si> are set to the group and sub-item status
of each item. The group, contained in the attribute C<mv_mi>, is a
meaningless yet unique integer. All items in a group will have the same
value of C<mv_mi>. The attribute C<mv_si> is set to 0 if the item is
a master item, and 1 if it is a sub-item.
H2: Basket display
The basket page(s) are where the items are tracked and adjusted by the
customer. It is possible to have an unlimited number of basket pages.
It is also possible to have multiple shopping carts, as in buy or
sell. This allows a basket/checkout type of ordering scheme, with custom
order pages for items which have many accessories.
The name of the page to display can be configured in several
ways:
^ Set the SpecialPage C<order> to the page to display
when an item is ordered.
+ Use the C<[order code=item page=page_name] Order it! </aE<gt>> form of
order tag to specify an arbitrary order page for an item.
+ If already on an order page, set the mv_orderpage,
mv_nextpage, mv_successpage, or mv_failpage variables.
The following variables can be used to control cart selection and
page display:
=over 4
=item mv_cartname
The shopping cart (default is main) to be used for this order
operation.
=item mv_failpage
Page to be displayed on a failed order
check (see I<Advanced Multi-level Order Pages>)
=item mv_nextpage
Page to display on a return operation.
=item mv_orderpage
Page to be displayed on a refresh.
=item mv_successpage
Page to be displayed on a successful order
check (see I<Advanced Multi-level Order Pages>).
=item mv_order_profile
Order profile to be used if the form action is F<submit>
(see I<Advanced Multi-level Order Pages>).
=back
H2: Multiple Shopping Carts
Interchange allows you to define and maintain multiple shopping carts.
One shopping cart -- main, by name -- is defined when the user session
starts. If the user orders item M1212 with the following tag:
> [order code=M1212 cart=layaway] Order this item! </a>
the order will be placed in the cart named I<layaway>. However, by default
you won't see the just-ordered item on the basket page. That is because
the default shopping basket displays the contents of the 'main' cart only.
So copy the default basket page (pages/ord/basket.html in the demo)
to a new file, insert a C<[cart layaway]> tag, and specify it as the target
page in your C<[order]> tag:
> [order code=M1212 cart=layaway page=ord/lay_basket] Order this item! </a>
Now the contents of the I<layaway> cart will be displayed. Most of the ITL
tags that are fundamental to cart display accept a 'cartname' option,
allowing you to specify which cart to be used:
=over 4
=item [cart cartname]
A 'sticky' setting of the default cart name to use for all subsequent
cart-related tags. Convenient, but you must remember to use C<[cart main]>
to get back to the primary cart! As an alternative, you can specify the
desired cart as a parameter of the other tags. These are not sticky,
referencing the specified cart only for the instance in which they are called:
=item [item-list cartname]...[/item-list]
Iterates over the items in the specified cart - tags like C<[item-quantity]>
and C<[item-price]> will be evaluated accordingly;
=item [nitems cartname]
Returns the total number of items in the specified cart;
=item [subtotal cartname]
Returns the monetary subtotal for the contents of specified cart;
=item [shipping cartname], [handling cartname], [salestax cartname], [total-cost cartname]
You get the idea. It is worth noting that tags which summarize
cart contents do not need to be in used concert, or in conjunction with
an C<[item-list]>. For instance, you can display just the grand
total for a cart on the sidebar or bottom of each page, using
C<[total-cost]> by itself, if you wish.
=back
You can also order items from a form, using the C<mv_order_item>,
C<mv_cartname>, and optional C<mv_order_quantity> variables.
> <FORM METHOD=POST ACTION="[process]">
> <input type=checkbox name="mv_order_item" value="M3243"> Item M3243
> <input name="mv_order_quantity" value="1"> Quantity
> <input type=hidden name="mv_cartname" value="layaway">
> <input type=hidden name="mv_doit" value="refresh">
> <input type=submit name="mv_junk" value="Place on Layaway Now!">
> </FORM>
If you need to utilize an alternative item price in conjunction with
the use of a custom cart, see the section on I<PRODUCT PRICING> for
pricing methods and strategies.
H1: PRODUCT PRICING
Interchange maintains a price in its database for every product. The price
field is the one required field in the product database -- it is necessary
to build the price routines.
For speed, Interchange builds the code that is used to determine a product's
price at catalog configuration time. If you choose to change a directive
that affects product pricing you must reconfigure the catalog.
H2: Simple pricing
The simplest method is flat pricing based on a fixed value in
the C<products> database. If you put that price in a field named
C<price>, you don't need to do more. If you want to change pricing
based on quantity, size, color or other factors read on.
H2: Price Maintenance with CommonAdjust
A flexible chained pricing scheme is available
when the I<CommonAdjust> directive is set.
We talk below about a I<CommonAdjust string>; it will be defined
in due time.
A few rules about CommonAdjust, all assuming the I<PriceField> directive
is set to C<price>:
LI1: 1
If C<CommonAdjust> is set to any value, a valid I<CommonAdjust string> or
not, extended price adjustments are enabled. It may also hold the
default pricing scheme.
LI1: 2
The C<price> field may also hold a I<CommonAdjust string>. It takes
precedence over the default.
LI1: 3
If the value of the C<CommonAdjust> directive is set to a CommonAdjust
string, and the C<price> field is empty or specifically I<0>, then it
will be used to set the price of the items.
LI1: 4
If no CommonAdjust strings are found, then the price will be 0, subject
to any later application of discounts.
LI1: 5
If another CommonAdjust string is found as the result of an operation,
it will be re-parsed and the result applied. Chaining is retained; a
fallback may be passed and will take effect.
Prices may be adjusted in several ways, and the individual actions
are referred to below as I<atoms>. Price atoms may be I<final>,
I<chained>, or I<fallback>. A final price atom is always applied if it
does not evaluate to zero. A chained price atom is subject to further
adjustment. A fallback price atom is skipped if a previous chained price
was not zero.
Atoms are separated by whitespace, and may be quoted (although there
should not normally be whitespace in a setting). A chained item ends
with a comma. A fallback item has a leading semi-colon. Final atoms
have no comma appended or semi-colon prepended.
A I<settor> is the means by which the price is set.
There are eight different types of price settors. All settors
can then yield another CommonAdjust string.
It is quite possible to create endless loops, so the maximum
number of initial CommonAdjust strings is set to 16, and there
may be only 32 iterations by default before the price will return zero on
an error. (The maximum iterations is specified with
the {{CMD[jump="icconfig.html#Limit"]Limit}} directive.)
B<NOTE>: Common needs are easily shown but not so easily explained;
skip to the examples in the reference below if your vision starts to
blur when reading the next section. 8-)
\USAGE: Optional items below have asterisks appended. The asterisk should
not be used in the actual string. Optional B<base> or B<table> always
defaults to the active C<products> database table. The optional B<key>
defaults to the item code except in a special case for the attribute-based
lookup. The B<field> name is not optional except in the case of an
attribute lookup.
=item N.NN or -N.NN
where N is a digit. A number which is applied directly; for instance
10 will yield a price of 10. May be a positive or negative number.
=item N.NN%
where N is a digit. A number which is applied as a percentage of
the I<current> price value. May be a positive or negative number. For
example, if the price is 10 and -8% is applied, the next price value
will be 9.20.
=item table*:column:key*
Causes a straight lookup in a database table. The optional B<table>
defaults to the main products database table for the item (subject
of course to multiple product files). The B<column> must always
be present. The optional B<key> defaults to the item code except
in a special case for the attribute-based lookup. The return value
is then re-parsed as another price settor.
=item table*:col1..col5,col10:key*
Causes a quantity lookup in database table B<table> (which defaults to
the products database), with a set of comma-separated fields, looked
up by the optional B<key>. (Key defaults to the item code, of course).
If ranges are specified with .., each column in the sequence will be used;
Therefore
> pricing:p1,p2,p3,p4,p5,p10:
is the same as
> pricing:p1..p5,p10:
Leading non-digits are stripped, and the item quantity is compared with
the numerical portion of the column name. The price is set to the value of
the database column (numeric portion) that is at least equal to it but
doesn't yet reach the next break.
\WARNING: If the field at the appropriate quantity level is blank,
a zero cost will be returned from the atom. It is important to
have all columns populated.
=item ==attribute:table*:column*:key*
Does an attribute-based adjustment. The attribute is looked up in the
database B<table>, with the optional B<column> defaulting to the same
name as the I<value> of the B<attribute>. If the column is not left blank,
the I<key> is set to the I<value> of the B<attribute> if blank.
=item & CODE
The leading C<&> sign is stripped and the code is passed to the
equivalent of a C<[calc]> tag. No Interchange tags can be used, but
the &tag_data routine is available, the current value of the price
and quantity are available as C<$s>, and the current item (code, quantity,
price, and any attributes) are available as C<$item>, all forced
to the package Vend::Interpolate. That means that in a UserTag:
> $Vend::Interpolate::item is the current item
> $Vend::Interpolate::item->{code} gives key for current item
> $Vend::Interpolate::item->{size} gives size for current item (if there)
> $Vend::Interpolate::item->{mv_ib} gives database ordered from
=item [valid Interchange tags]
If the settor begins with a square bracket (C<[>) or underscore, it
is parsed for Interchange tags with variable substitution (but no Locale
substitution). You may define a price in a I<Variable> in this fashion.
The string is re-submitted as an atom, so it may yield yet another
settor.
=item $
Tells Interchange to look in the C<mv_price> attribute of the shopping cart,
and apply that price as the final price, if it exists. The attribute must
be a numerical value.
=item >>word
Tells the routine to return C<word> directly as the result. This is not
useful in pricing, as it will evaluate to zero. But when CommonAdjust
is used for shipping, it is a way of re-directing shipping modes.
=item word
The value of C<word>, which must not match any of the other settors,
is available as a key for the next lookup (only). If the next settor
is a database lookup, and it contains a dollar sign (C<$>) the C<word>
will be substituted; i.e. C<table:column:$> becomes C<table:column:word>.
=item ( settor )
The value returned by C<settor> will be used as a key for the next
lookup, as above.
=back
H2: CommonAdjust Examples
Most examples below use an outboard database table named B<pricing>, but
any valid table including the B<products> table can be used. We will refer
to this B<pricing> table:
> code common q1 q5 q10 XL S red
> 99-102 10 9 8 1 -0.50 0.75
> 00-343 2
> red 0.75
The simplest case is a straight lookup on an attribute; I<size> in this
case.
> 10.00, ==size:pricing
With this value in the C<price> field, a base price of 10.00 will be
adjusted with the value of the I<size> attribute. If size for the item
99-102 is set to C<XL> then 1.00 will be added for a total price of 11.00;
if it is C<S> then .50 will be subtracted for a total price of 9.50;
for any other value of I<size> no further adjustment would be made. 00-343
would be adjusted up 2.00 only for I<XL>.
> 10.00, ==size:pricing, ==color:pricing
This is the same as above, except both size and color are adjusted for.
A color value of red for item code 99-102 would add 0.75 to the price. For
00-343 it would have no effect.
> 10.00, ==size:pricing, ==color:pricing:common
Here price is set based on a common column, keyed by the value of the
color attribute. Any item with a color value of red would have 0.75 added
to the base price.
> pricing:q1,q5,q10:, ;10.00, ==size:pricing, ==color:pricing:common
Here is a quantity price lookup, with a fallback price setting. If there
is a valid price found at the quantity of 1, 5, or 10, depending on
item quantity, then it will be used. The fallback of 10.00 only applies if no
non-zero/non-blank price was found at the quantity lookup. In either
case, size/color adjustment is applied.
> pricing:q1,q5,q10:, ;10.00 ==size:pricing, ==color:pricing:common
Removing the comma from the end of the fallback string stops color/size
lookup if it reaches that point. If a quantity price was found, then size
and color are chained.
> pricing:q1,q5,q10:, ;products:list_price, ==size:pricing, ==color:pricing
The value of the database column C<list_price> is used as a fallback
instead of the fixed 10.00 value. The above value might be a nice one
to use as the default for a typical retail catalog that has items with
colors and sizes.
H2: PriceBreaks, discounts, and PriceAdjustment
There are several ways that Interchange can modify the price of a product during
normal catalog operation. Several of them require that the I<pricing.asc>
file be present, and that you define a pricing database. You do that by
placing the following directive in I<catalog.cfg>:
> Database pricing pricing.asc 1
\NOTE: PriceAdjustment is slightly deprecated by CommonAdjust, but
will remain in use at least through the end of Version 3 of Interchange.
Configurable directives and tags with regard to pricing:
=over 4
=item *
Quantity price breaks are configured by means of the I<PriceBreaks> and
I<MixMatch> directives. They require a field named specifically C<price>
in the pricing database. The B<price> field contains a space-separated
list of prices that correspond to the quantity levels defined in the
F<PriceBreaks> directive. If quantity is to be applied to all items in
the shopping cart (as opposed to quantity of just that item) then the
I<MixMatch> directive should be set to B<Yes>.
=item *
Individual line-item prices can be adjusted according to the value of
their attributes. See I<PriceAdjustment> and I<CommonAdjust>. The
pricing database B<must> be defined unless you define the F<CommonAdjust>
behavior.
=item *
Product discounts for individual products, specific product codes,
all products, or the entire order can be configured with the C<[discount ...]>
tag. Discounts are applied on a per-user basis -- you can gate the
discount based on membership in a club or other arbitrary means. See
I<Product Discounts>.
=back
For example, if you decided to adjust the price of T-shirt part number
99-102 up 1.00 when the size is extra large and down 1.00 when the size is small,
you would have the following directives defined in <catalog.cfg>:
> Database pricing pricing.asc 1
> UseModifier size
> PriceAdjustment size
To enable automatic modifier handling, you define a size field in
products.txt:
> code description price size
> 99-102 T-Shirt 10.00 S=Small, M=Medium, L=Large*, XL=Extra Large
You would place the proper tag within your C<[item-list]> on the shopping-basket
or order page:
> [item-accessories size]
In the pricing.asc database source, you would need:
> code S XL
> 99-102 -1.00 1.00
If you want to assign a price based on the option, precede the number
with an equals sign:
> code S M L XL
> 99-102 =9.00 =10 =10 =11
IMPORTANT NOTE: Price adjustments occur AFTER quantity price breaks, so
the above would negate anything set with the I<PriceBreaks> directive/option.
Numbers that begin with an equals sign (C<=>) are used as absolute
prices and are I<interpolated for Interchange tags first>, so you can
use subroutines to set the price. To facilitate coordination with the
subroutine, the session variables C<item_code> and C<item_quantity> are
set to the code and quantity of the item being evaluated. They would
be accessed in a global subroutine with C<$Vend::Session->>C<{item_code}>
and C<$Vend::Session->>C<{item_quantity}>.
The pricing information must always come from a database because
of security.
H2: Item Attributes
Interchange allows item attributes to be set for each ordered item. This
allows a size, color, or other modifier to be attached to a common
part number. If multiple attributes are set, then they should be
separated by commas. Previous attribute values can be saved by means
of a hidden field on a form, and multiple attributes for each item
can be I<stacked> on top of each other.
The configuration file directive I<UseModifier> is used to set
the name of the modifier or modifiers. For example
> UseModifier size,color
will attach both a size and color attribute to each item code that
is ordered.
B<IMPORTANT NOTE:> You may not use the following names for attributes:
> item group quantity code mv_ib mv_mi mv_si
You can also set it in scratch with the mv_UseModifier
scratch variable -- C<[set mv_UseModifier]size color[/set]> has the
same effect as above. This allows multiple options to be set for
products. Whichever one is in effect at order time will be used.
Be careful, you cannot set it more than once on the same page.
Setting the C<mv_separate_items> or global directive I<SeparateItems>
places each ordered item on a separate line, simplifying attribute
handling. The scratch setting for C<mv_separate_items> has the same
effect.
The modifier value is accessed in the C<[item-list]> loop with the
C<[item-modifier attribute]> tag, and form input fields are placed with the
C<[modifier-name attribute]> tag. This is similar to the way that quantity
is handled, except that attributes can be "stacked" by setting multiple
values in an input form.
You cannot define a modifier name of I<code> or I<quantity>, as they
are already used. You must be sure that no fields in your forms
have digits appended to their names if the variable is the same name
as the attribute name you select, as the C<[modifier-name size]> variables
will be placed in the user session as the form variables size0, size1,
size2, etc.
You can use the C<[loop arg="item item item"]> list to reference multiple display
or selection fields for modifiers, or you can use the built-in
C<[PREFIX-accessories ...]> tags available in most Interchange list operations.
The modifier value can then be used to select data from an arbitrary database
for attribute selection and display.
Below is a fragment from a shopping basket display form which
shows a selectable size with "sticky" setting. Note that this
would always be contained within the C<[item_list]> C<[/item-list]>
pair.
> <SELECT NAME="[modifier-name size]">
> <OPTION [selected [modifier-name size] S]> S
> <OPTION [selected [modifier-name size] M]> M
> <OPTION [selected [modifier-name size] L]> L
> <OPTION [selected [modifier-name size] XL]> XL
> </SELECT>
It could just as easily be done with a radio button group combined
with the C<[checked ...]> tag.
Interchange will automatically generate the above select box
when the C<[accessories <code> size]> or C<[item-accessories size]>
tags are called. They have the syntax:
> [item_accessories attribute*, type*, field*, database*, name*, outboard*]
>
> [accessories code attribute*, type*, field*, database*, name*, outboard*]
=over 4
=item code
Not needed for item-accessories, this is the product code of the item to
reference.
=item attribute
The item attribute as specified in the UseModifier configuration
directive. Typical are C<size> or C<color>.
=item type
The action to be taken. One of:
> select Builds a dropdown <SELECT> menu for the attribute.
> NOTE: This is the default.
>
> multiple Builds a multiple dropdown <SELECT> menu for the
> attribute. The size is equal to the number of
> option choices.
>
> display Shows the label text for *only the selected option*.
>
> show Shows the option choices (no labels) for the option.
>
> radio Builds a radio box group for the item, with spaces
> separating the elements.
>
> radio nbsp Builds a radio box group for the item, with
> separating the elements.
>
> radio left n Builds a radio box group for the item, inside a
> table, with the checkbox on the left side. If "n"
> is present and is a digit from 2 to 9, it will align
> the options in that many columns.
>
> radio right n Builds a radio box group for the item, inside a
> table, with the checkbox on the right side. If "n"
> is present and is a digit from 2 to 9, it will align
> the options in that many columns.
>
> check Builds a checkbox group for the item, with spaces
> separating the elements.
>
> check nbsp Builds a checkbox group for the item, with
> separating the elements.
>
> check left n Builds a checkbox group for the item, inside a
> table, with the checkbox on the left side. If "n"
> is present and is a digit from 2 to 9, it will align
> the options in that many columns.
>
> check right n Builds a checkbox group for the item, inside a
> table, with the checkbox on the right side. If "n"
> is present and is a digit from 2 to 9, it will align
> the options in that many columns.
The default is 'select', which builds an HTML select form entry for
the attribute. Also recognized is 'multiple', which generates a
multiple-selection drop down list, 'show', which shows the list of
possible attributes, and 'display', which shows the label text for the
selected option only.
=item field
The database field name to be used to build the entry (usually a field
in the products database). Defaults to a field named the same as the
attribute.
=item database
The database to find B<field> in, defaults to the first products file
where the item code is found.
=item name
Name of the form variable to use if a form is being built. Defaults to
mv_order_B<attribute> -- i.e. if the attribute is B<size>, the form
variable will be named B<mv_order_size>.
=item outboard
If calling the item-accessories tag, and you wish to select from an
outboard database, you can pass the key to use to find the accessory
data.
=back
When called with an attribute, the database is consulted and looks for
a comma-separated list of attribute options. They take the form:
> name=Label Text, name=Label Text*
The label text is optional -- if none is given, the B<name> will
be used.
If an asterisk is the last character of the label text, the item is
the default selection. If no default is specified, the first will be
the default. An example:
> [item_accessories color]
This will search the product database for a field named "color". If
an entry "beige=Almond, gold=Harvest Gold, White*, green=Avocado" is found,
a select box like this will be built:
> <SELECT NAME="mv_order_color">
> <OPTION VALUE="beige">Almond
> <OPTION VALUE="gold">Harvest Gold
> <OPTION SELECTED>White
> <OPTION VALUE="green">Avocado
> </SELECT>
In combination with the C<mv_order_item> and C<mv_order_quantity> variables
this can be used to allow entry of an attribute at time of order.
If used in an item list, and the user has changed the value, the generated
select box will automatically retain the current value the user has selected.
The value can then be displayed with C<[item-modifier size]> on the
order report, order receipt, or any other page containing an
C<[item-list]>.
H2: Product Discounts
Product discounts can be set upon display of any page. The discounts
apply only to the customer receiving them, and are of one of three types:
> 1. A discount for one particular item code (key is the item-code)
> 2. A discount applying to all item codes (key is ALL_ITEMS)
> 3. A discount for an individual line item (set the mv_discount attribute
> with embedded Perl)
> 4. A discount applied after all items are totaled
> (key is ENTIRE_ORDER)
The discounts are specified via a formula. The formula is scanned for
the variables $q and $s, which are substituted for with the item
I<quantity> and I<subtotal> respectively. The variable $s is saved between
iterations, so the discounts are cumulative. In the case of the item and
all items discount, the formula must evaluate to a new subtotal for all
items I<of that code> that are ordered. The discount for the entire
order is applied to the entire order, and would normally be a monetary