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
49static 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 */
81void 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