1 | /* |
2 | * Legal Notice |
3 | * |
4 | * This document and associated source code (the "Work") is a part of a |
5 | * benchmark specification maintained by the TPC. |
6 | * |
7 | * The TPC reserves all right, title, and interest to the Work as provided |
8 | * under U.S. and international laws, including without limitation all patent |
9 | * and trademark rights therein. |
10 | * |
11 | * No Warranty |
12 | * |
13 | * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION |
14 | * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE |
15 | * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER |
16 | * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, |
17 | * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES, |
18 | * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR |
19 | * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF |
20 | * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE. |
21 | * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, |
22 | * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT |
23 | * WITH REGARD TO THE WORK. |
24 | * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO |
25 | * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE |
26 | * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS |
27 | * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT, |
28 | * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY, |
29 | * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT |
30 | * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD |
31 | * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. |
32 | * |
33 | * Contributors: |
34 | * Gradient Systems |
35 | */ |
36 | #include "config.h" |
37 | #include "porting.h" |
38 | #include <stdio.h> |
39 | #include "decimal.h" |
40 | #include "pricing.h" |
41 | #include "constants.h" |
42 | #include "columns.h" |
43 | #include "error_msg.h" |
44 | #include "dist.h" |
45 | #include "genrand.h" |
46 | #include "w_web_sales.h" |
47 | |
48 | #define MAX_LIMIT 12 |
49 | static ds_limits_t aPriceLimits[MAX_LIMIT] = { |
50 | {CS_PRICING, CS_QUANTITY_MAX, CS_MARKUP_MAX, CS_DISCOUNT_MAX, CS_WHOLESALE_MAX, CS_COUPON_MAX}, |
51 | {SS_PRICING, SS_QUANTITY_MAX, SS_MARKUP_MAX, SS_DISCOUNT_MAX, SS_WHOLESALE_MAX, SS_COUPON_MAX}, |
52 | {WS_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
53 | {CR_PRICING, CS_QUANTITY_MAX, CS_MARKUP_MAX, CS_DISCOUNT_MAX, CS_WHOLESALE_MAX, CS_COUPON_MAX}, |
54 | {SR_PRICING, SS_QUANTITY_MAX, SS_MARKUP_MAX, SS_DISCOUNT_MAX, SS_WHOLESALE_MAX, SS_COUPON_MAX}, |
55 | {WR_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
56 | {S_PLINE_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
57 | {S_CLIN_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
58 | {S_WLIN_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
59 | {S_SRET_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
60 | {S_CRET_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX}, |
61 | {S_WRET_PRICING, WS_QUANTITY_MAX, WS_MARKUP_MAX, WS_DISCOUNT_MAX, WS_WHOLESALE_MAX, WS_COUPON_MAX} |
62 | |
63 | }; |
64 | |
65 | /* |
66 | * Routine: set_pricing(int nTabId, ds_pricing_t *pPricing) |
67 | * Purpose: handle the various pricing calculations for the fact tables |
68 | * Notes: |
69 | * the RNG usage is not kept in sync between sales pricing and returns pricing. |
70 | *If the calculations look wrong, it may be necessary to "waste" some RNG calls |
71 | *on one side or the other to bring things back in line Data Structures: |
72 | * |
73 | * Params: |
74 | * Returns: |
75 | * Called By: |
76 | * Calls: |
77 | * Assumptions: |
78 | * Side Effects: |
79 | * TODO: None |
80 | */ |
81 | void set_pricing(int nTabId, ds_pricing_t *pPricing) { |
82 | static int nLastId = -1, init = 0, nQuantityMax, nQuantityMin = 1; |
83 | static decimal_t dQuantity, dMarkupMin, dDiscountMin, dWholesaleMin, dMarkupMax, dDiscountMax, dWholesaleMax, |
84 | dCouponMin, dCouponMax, dZero, dOneHalf, d9pct, dOne, dTemp, dHundred; |
85 | decimal_t dMarkup, dCoupon, dShipping, dDiscount, dTemp2; |
86 | int i, nCashPct, nCreditPct, nCouponUsage; |
87 | |
88 | if (!init) { |
89 | strtodec(&dMarkupMin, "0.00" ); |
90 | strtodec(&dDiscountMin, "0.00" ); |
91 | strtodec(&dWholesaleMin, "1.00" ); |
92 | strtodec(&dCouponMin, "0.00" ); |
93 | strtodec(&dZero, "0.00" ); |
94 | strtodec(&dOneHalf, "0.50" ); |
95 | strtodec(&d9pct, "0.09" ); |
96 | strtodec(&dWholesaleMin, "1.00" ); |
97 | strtodec(&dHundred, "100.00" ); |
98 | strtodec(&dOne, "1.00" ); |
99 | |
100 | init = 1; |
101 | } |
102 | |
103 | if (nTabId != nLastId) { |
104 | nLastId = -1; |
105 | for (i = 0; i < MAX_LIMIT; i++) { |
106 | if (nTabId == aPriceLimits[i].nId) |
107 | nLastId = i; |
108 | } |
109 | if (nLastId == -1) |
110 | INTERNAL("No pricing limits defined" ); |
111 | nQuantityMax = atoi(aPriceLimits[nLastId].szQuantity); |
112 | strtodec(&dDiscountMax, aPriceLimits[nLastId].szDiscount); |
113 | strtodec(&dMarkupMax, aPriceLimits[nLastId].szMarkUp); |
114 | strtodec(&dWholesaleMax, aPriceLimits[nLastId].szWholesale); |
115 | strtodec(&dCouponMax, aPriceLimits[nLastId].szCoupon); |
116 | } |
117 | |
118 | switch (nTabId) { |
119 | case SS_PRICING: |
120 | case CS_PRICING: |
121 | case WS_PRICING: |
122 | case S_PLINE_PRICING: |
123 | case S_CLIN_PRICING: |
124 | case S_WLIN_PRICING: |
125 | genrand_integer(&pPricing->quantity, DIST_UNIFORM, nQuantityMin, nQuantityMax, 0, nTabId); |
126 | itodec(&dQuantity, pPricing->quantity); |
127 | genrand_decimal(&pPricing->wholesale_cost, DIST_UNIFORM, &dWholesaleMin, &dWholesaleMax, NULL, nTabId); |
128 | |
129 | /* ext_wholesale_cost = wholesale_cost * quantity */ |
130 | decimal_t_op(&pPricing->ext_wholesale_cost, OP_MULT, &dQuantity, &pPricing->wholesale_cost); |
131 | |
132 | /* list_price = wholesale_cost * (1 + markup) */ |
133 | genrand_decimal(&dMarkup, DIST_UNIFORM, &dMarkupMin, &dMarkupMax, NULL, nTabId); |
134 | decimal_t_op(&dMarkup, OP_PLUS, &dMarkup, &dOne); |
135 | decimal_t_op(&pPricing->list_price, OP_MULT, &pPricing->wholesale_cost, &dMarkup); |
136 | |
137 | /* sales_price = list_price * (1 - discount)*/ |
138 | genrand_decimal(&dDiscount, DIST_UNIFORM, &dDiscountMin, &dDiscountMax, NULL, nTabId); |
139 | NegateDecimal(&dDiscount); |
140 | decimal_t_op(&pPricing->ext_discount_amt, OP_PLUS, &dDiscount, &dOne); |
141 | decimal_t_op(&pPricing->sales_price, OP_MULT, &pPricing->list_price, &pPricing->ext_discount_amt); |
142 | |
143 | /* ext_list_price = list_price * quantity */ |
144 | decimal_t_op(&pPricing->ext_list_price, OP_MULT, &pPricing->list_price, &dQuantity); |
145 | |
146 | /* ext_sales_price = sales_price * quantity */ |
147 | decimal_t_op(&pPricing->ext_sales_price, OP_MULT, &pPricing->sales_price, &dQuantity); |
148 | |
149 | /* ext_discount_amt = ext_list_price - ext_sales_price */ |
150 | decimal_t_op(&pPricing->ext_discount_amt, OP_MINUS, &pPricing->ext_list_price, &pPricing->ext_sales_price); |
151 | |
152 | /* coupon_amt = ext_sales_price * coupon */ |
153 | genrand_decimal(&dCoupon, DIST_UNIFORM, &dZero, &dOne, NULL, nTabId); |
154 | genrand_integer(&nCouponUsage, DIST_UNIFORM, 1, 100, 0, nTabId); |
155 | if (nCouponUsage <= 20) /* 20% of sales employ a coupon */ |
156 | decimal_t_op(&pPricing->coupon_amt, OP_MULT, &pPricing->ext_sales_price, &dCoupon); |
157 | else |
158 | memcpy(&pPricing->coupon_amt, &dZero, sizeof(decimal_t)); |
159 | |
160 | /* net_paid = ext_sales_price - coupon_amt */ |
161 | decimal_t_op(&pPricing->net_paid, OP_MINUS, &pPricing->ext_sales_price, &pPricing->coupon_amt); |
162 | |
163 | /* shipping_cost = list_price * shipping */ |
164 | genrand_decimal(&dShipping, DIST_UNIFORM, &dZero, &dOneHalf, NULL, nTabId); |
165 | decimal_t_op(&pPricing->ship_cost, OP_MULT, &pPricing->list_price, &dShipping); |
166 | |
167 | /* ext_shipping_cost = shipping_cost * quantity */ |
168 | decimal_t_op(&pPricing->ext_ship_cost, OP_MULT, &pPricing->ship_cost, &dQuantity); |
169 | |
170 | /* net_paid_inc_ship = net_paid + ext_shipping_cost */ |
171 | decimal_t_op(&pPricing->net_paid_inc_ship, OP_PLUS, &pPricing->net_paid, &pPricing->ext_ship_cost); |
172 | |
173 | /* ext_tax = tax * net_paid */ |
174 | genrand_decimal(&pPricing->tax_pct, DIST_UNIFORM, &dZero, &d9pct, NULL, nTabId); |
175 | decimal_t_op(&pPricing->ext_tax, OP_MULT, &pPricing->net_paid, &pPricing->tax_pct); |
176 | |
177 | /* net_paid_inc_tax = net_paid + ext_tax */ |
178 | decimal_t_op(&pPricing->net_paid_inc_tax, OP_PLUS, &pPricing->net_paid, &pPricing->ext_tax); |
179 | |
180 | /* net_paid_inc_ship_tax = net_paid_inc_tax + ext_shipping_cost */ |
181 | decimal_t_op(&pPricing->net_paid_inc_ship_tax, OP_PLUS, &pPricing->net_paid_inc_ship, &pPricing->ext_tax); |
182 | |
183 | /* net_profit = net_paid - ext_wholesale_cost */ |
184 | decimal_t_op(&pPricing->net_profit, OP_MINUS, &pPricing->net_paid, &pPricing->ext_wholesale_cost); |
185 | break; |
186 | case CR_PRICING: |
187 | case SR_PRICING: |
188 | case WR_PRICING: |
189 | /* quantity is determined before we are called */ |
190 | /* ext_wholesale_cost = wholesale_cost * quantity */ |
191 | itodec(&dQuantity, pPricing->quantity); |
192 | decimal_t_op(&pPricing->ext_wholesale_cost, OP_MULT, &dQuantity, &pPricing->wholesale_cost); |
193 | |
194 | /* ext_list_price = list_price * quantity */ |
195 | decimal_t_op(&pPricing->ext_list_price, OP_MULT, &pPricing->list_price, &dQuantity); |
196 | |
197 | /* ext_sales_price = sales_price * quantity */ |
198 | decimal_t_op(&pPricing->ext_sales_price, OP_MULT, &pPricing->sales_price, &dQuantity); |
199 | |
200 | /* net_paid = ext_list_price (couppons don't effect returns) */ |
201 | memcpy(&pPricing->net_paid, &pPricing->ext_sales_price, sizeof(decimal_t)); |
202 | |
203 | /* shipping_cost = list_price * shipping */ |
204 | genrand_decimal(&dShipping, DIST_UNIFORM, &dZero, &dOneHalf, NULL, nTabId); |
205 | decimal_t_op(&pPricing->ship_cost, OP_MULT, &pPricing->list_price, &dShipping); |
206 | |
207 | /* ext_shipping_cost = shipping_cost * quantity */ |
208 | decimal_t_op(&pPricing->ext_ship_cost, OP_MULT, &pPricing->ship_cost, &dQuantity); |
209 | |
210 | /* net_paid_inc_ship = net_paid + ext_shipping_cost */ |
211 | decimal_t_op(&pPricing->net_paid_inc_ship, OP_PLUS, &pPricing->net_paid, &pPricing->ext_ship_cost); |
212 | |
213 | /* ext_tax = tax * net_paid */ |
214 | decimal_t_op(&pPricing->ext_tax, OP_MULT, &pPricing->net_paid, &pPricing->tax_pct); |
215 | |
216 | /* net_paid_inc_tax = net_paid + ext_tax */ |
217 | decimal_t_op(&pPricing->net_paid_inc_tax, OP_PLUS, &pPricing->net_paid, &pPricing->ext_tax); |
218 | |
219 | /* net_paid_inc_ship_tax = net_paid_inc_tax + ext_shipping_cost */ |
220 | decimal_t_op(&pPricing->net_paid_inc_ship_tax, OP_PLUS, &pPricing->net_paid_inc_ship, &pPricing->ext_tax); |
221 | |
222 | /* net_profit = net_paid - ext_wholesale_cost */ |
223 | decimal_t_op(&pPricing->net_profit, OP_MINUS, &pPricing->net_paid, &pPricing->ext_wholesale_cost); |
224 | |
225 | /* see to it that the returned amounts add up to the total returned */ |
226 | /* allocate some of return to cash */ |
227 | genrand_integer(&nCashPct, DIST_UNIFORM, 0, 100, 0, nTabId); |
228 | itodec(&dTemp, nCashPct); |
229 | decimal_t_op(&pPricing->refunded_cash, OP_DIV, &dTemp, &dHundred); |
230 | decimal_t_op(&pPricing->refunded_cash, OP_MULT, &pPricing->refunded_cash, &pPricing->net_paid); |
231 | |
232 | /* allocate some to reversed charges */ |
233 | genrand_integer(&nCreditPct, DIST_UNIFORM, 1, 100, 0, nTabId); |
234 | itodec(&dTemp2, nCreditPct); |
235 | decimal_t_op(&dTemp, OP_DIV, &dTemp2, &dHundred); |
236 | decimal_t_op(&dTemp2, OP_MINUS, &pPricing->net_paid, &pPricing->refunded_cash); |
237 | decimal_t_op(&pPricing->reversed_charge, OP_MULT, &dTemp2, &dTemp); |
238 | |
239 | /* the rest is store credit */ |
240 | decimal_t_op(&pPricing->store_credit, OP_MINUS, &pPricing->net_paid, &pPricing->reversed_charge); |
241 | decimal_t_op(&pPricing->store_credit, OP_MINUS, &pPricing->store_credit, &pPricing->refunded_cash); |
242 | |
243 | /* pick a fee for the return */ |
244 | genrand_decimal(&pPricing->fee, DIST_UNIFORM, &dOneHalf, &dHundred, &dZero, nTabId); |
245 | |
246 | /* and calculate the net effect */ |
247 | decimal_t_op(&pPricing->net_loss, OP_MINUS, &pPricing->net_paid_inc_ship_tax, &pPricing->store_credit); |
248 | decimal_t_op(&pPricing->net_loss, OP_MINUS, &pPricing->net_loss, &pPricing->refunded_cash); |
249 | decimal_t_op(&pPricing->net_loss, OP_MINUS, &pPricing->net_loss, &pPricing->reversed_charge); |
250 | decimal_t_op(&pPricing->net_loss, OP_PLUS, &pPricing->net_loss, &pPricing->fee); |
251 | break; |
252 | } |
253 | |
254 | return; |
255 | } |
256 | |