hvp-shared 6.45.1 → 6.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants/pricing.constants.d.ts +25 -2
- package/dist/constants/pricing.constants.js +62 -8
- package/dist/constants/pricing.constants.test.js +82 -10
- package/dist/contracts/catalog-item/requests.d.ts +4 -0
- package/dist/contracts/catalog-item/responses.d.ts +4 -0
- package/package.json +1 -1
|
@@ -25,8 +25,6 @@ export declare enum PricePolicy {
|
|
|
25
25
|
EXT_COST = "EXT_COST",
|
|
26
26
|
/** Internal services (priced by market study / competition) */
|
|
27
27
|
COMP_SVC = "COMP_SVC",
|
|
28
|
-
/** Diagnostic tests (TBD — no formula yet) */
|
|
29
|
-
TEST = "TEST",
|
|
30
28
|
/** Individual formula per item */
|
|
31
29
|
SPECIAL = "SPECIAL",
|
|
32
30
|
/** Fixed manual price (no formula) */
|
|
@@ -130,4 +128,29 @@ export declare function calculateRecommendedPricePVP(params: {
|
|
|
130
128
|
unitPurchasePriceBI: number;
|
|
131
129
|
vatSalePercent: number;
|
|
132
130
|
}): number | null;
|
|
131
|
+
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) */
|
|
132
|
+
export declare const MIN_PRICE_COST_FACTOR = 0.25;
|
|
133
|
+
/** Cost-based multiplier for floor price (EXT_COST) */
|
|
134
|
+
export declare const MIN_PRICE_EXT_COST_FACTOR = 1;
|
|
135
|
+
/** Fraction of salePricePVP for recommended minimum price (COMP_SVC) */
|
|
136
|
+
export declare const MIN_PRICE_COMP_SVC_SALE_FRACTION = 0.5;
|
|
137
|
+
export interface FloorPriceResult {
|
|
138
|
+
recommendedMinimumPrice: number | null;
|
|
139
|
+
floorPrice: number | null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Calculate floor prices (recommended minimum price and absolute floor) for a catalog item.
|
|
143
|
+
*
|
|
144
|
+
* Business rules by PricePolicy:
|
|
145
|
+
* - PHARM, PHARM_FRAC, COST_ML, COST: both = unitCostBI × 0.25 × (1 + VAT/100), round5
|
|
146
|
+
* - EXT_COST: both = unitCostBI × 1.0 × (1 + VAT/100), round5
|
|
147
|
+
* - COMP_SVC: recommendedMinimumPrice = salePricePVP × 0.50 (round5), floorPrice = 0
|
|
148
|
+
* - NONE, SPECIAL, MANUAL: both null
|
|
149
|
+
*/
|
|
150
|
+
export declare function calculateFloorPrices(params: {
|
|
151
|
+
pricePolicy: PricePolicy;
|
|
152
|
+
unitPurchasePriceBI: number;
|
|
153
|
+
vatSalePercent: number;
|
|
154
|
+
salePricePVP: number;
|
|
155
|
+
}): FloorPriceResult;
|
|
133
156
|
export {};
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* recommendedPrice = unitCostBI * markupFactor * (1 + vatSale/100)
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.ALLOWED_POLICIES_BY_SECTION = exports.COMP_SVC_SECTIONS = exports.NON_SELLABLE_SECTIONS = exports.NO_FORMULA_POLICIES = exports.AUTO_TIER_POLICIES = exports.AUTO_TIER_RANGES = exports.MARKUP_FACTORS = exports.PRICING_TIER_VALUES = exports.PRICE_POLICY_VALUES = exports.PRICING_TIER_LABELS = exports.PRICE_POLICY_LABELS = exports.PricingTier = exports.PricePolicy = void 0;
|
|
12
|
+
exports.MIN_PRICE_COMP_SVC_SALE_FRACTION = exports.MIN_PRICE_EXT_COST_FACTOR = exports.MIN_PRICE_COST_FACTOR = exports.ALLOWED_POLICIES_BY_SECTION = exports.COMP_SVC_SECTIONS = exports.NON_SELLABLE_SECTIONS = exports.NO_FORMULA_POLICIES = exports.AUTO_TIER_POLICIES = exports.AUTO_TIER_RANGES = exports.MARKUP_FACTORS = exports.PRICING_TIER_VALUES = exports.PRICE_POLICY_VALUES = exports.PRICING_TIER_LABELS = exports.PRICE_POLICY_LABELS = exports.PricingTier = exports.PricePolicy = void 0;
|
|
13
13
|
exports.getAutoTier = getAutoTier;
|
|
14
14
|
exports.getMarkupFactor = getMarkupFactor;
|
|
15
15
|
exports.getDefaultPricePolicy = getDefaultPricePolicy;
|
|
16
16
|
exports.calculateRecommendedPricePVP = calculateRecommendedPricePVP;
|
|
17
|
+
exports.calculateFloorPrices = calculateFloorPrices;
|
|
17
18
|
const qvet_catalog_1 = require("./qvet-catalog");
|
|
18
19
|
// =============================================================================
|
|
19
20
|
// ENUMS
|
|
@@ -37,8 +38,6 @@ var PricePolicy;
|
|
|
37
38
|
PricePolicy["EXT_COST"] = "EXT_COST";
|
|
38
39
|
/** Internal services (priced by market study / competition) */
|
|
39
40
|
PricePolicy["COMP_SVC"] = "COMP_SVC";
|
|
40
|
-
/** Diagnostic tests (TBD — no formula yet) */
|
|
41
|
-
PricePolicy["TEST"] = "TEST";
|
|
42
41
|
/** Individual formula per item */
|
|
43
42
|
PricePolicy["SPECIAL"] = "SPECIAL";
|
|
44
43
|
/** Fixed manual price (no formula) */
|
|
@@ -65,7 +64,6 @@ exports.PRICE_POLICY_LABELS = {
|
|
|
65
64
|
[PricePolicy.COST]: 'Insumos / Artículos (por costo)',
|
|
66
65
|
[PricePolicy.EXT_COST]: 'Servicios externos',
|
|
67
66
|
[PricePolicy.COMP_SVC]: 'Servicios internos (estudio de mercado)',
|
|
68
|
-
[PricePolicy.TEST]: 'Pruebas diagnósticas',
|
|
69
67
|
[PricePolicy.SPECIAL]: 'Fórmula individual',
|
|
70
68
|
[PricePolicy.MANUAL]: 'Precio manual',
|
|
71
69
|
[PricePolicy.NONE]: 'No se vende',
|
|
@@ -105,7 +103,6 @@ exports.AUTO_TIER_POLICIES = [
|
|
|
105
103
|
/** Policies that have no formula (recommendedPrice = null) */
|
|
106
104
|
exports.NO_FORMULA_POLICIES = [
|
|
107
105
|
PricePolicy.COMP_SVC,
|
|
108
|
-
PricePolicy.TEST,
|
|
109
106
|
PricePolicy.SPECIAL,
|
|
110
107
|
PricePolicy.MANUAL,
|
|
111
108
|
PricePolicy.NONE,
|
|
@@ -139,7 +136,7 @@ exports.ALLOWED_POLICIES_BY_SECTION = {
|
|
|
139
136
|
[qvet_catalog_1.QVET_SECTIONS.FARMACIA_INTERNA]: [PricePolicy.PHARM, PricePolicy.PHARM_FRAC, PricePolicy.COST_ML, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
140
137
|
[qvet_catalog_1.QVET_SECTIONS.INSUMOS_MEDICOS]: [PricePolicy.COST, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
141
138
|
[qvet_catalog_1.QVET_SECTIONS.OTROS_ARTICULOS]: [PricePolicy.COST, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
142
|
-
[qvet_catalog_1.QVET_SECTIONS.SERVICIOS_MEDICOS]: [PricePolicy.COMP_SVC, PricePolicy.
|
|
139
|
+
[qvet_catalog_1.QVET_SECTIONS.SERVICIOS_MEDICOS]: [PricePolicy.COMP_SVC, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
143
140
|
[qvet_catalog_1.QVET_SECTIONS.OTROS_SERVICIOS]: [PricePolicy.COMP_SVC, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
144
141
|
[qvet_catalog_1.QVET_SECTIONS.SERVICIOS_EXTERNOS]: [PricePolicy.EXT_COST, PricePolicy.SPECIAL, PricePolicy.MANUAL],
|
|
145
142
|
};
|
|
@@ -218,6 +215,13 @@ function getDefaultPricePolicy(section, saleUnit, conversionFactor) {
|
|
|
218
215
|
// Fallback: manual pricing
|
|
219
216
|
return { policy: PricePolicy.MANUAL, tier: null };
|
|
220
217
|
}
|
|
218
|
+
// =============================================================================
|
|
219
|
+
// ROUNDING HELPER
|
|
220
|
+
// =============================================================================
|
|
221
|
+
/** Round to nearest multiple of 5 */
|
|
222
|
+
function roundToNearest5(value) {
|
|
223
|
+
return Math.round(value / 5) * 5;
|
|
224
|
+
}
|
|
221
225
|
/**
|
|
222
226
|
* Calculate the recommended price PVP (con IVA) for a catalog item.
|
|
223
227
|
*
|
|
@@ -234,6 +238,56 @@ function calculateRecommendedPricePVP(params) {
|
|
|
234
238
|
return null;
|
|
235
239
|
const priceBI = unitPurchasePriceBI * factor;
|
|
236
240
|
const pricePVP = priceBI * (1 + vatSalePercent / 100);
|
|
237
|
-
|
|
238
|
-
|
|
241
|
+
return roundToNearest5(pricePVP);
|
|
242
|
+
}
|
|
243
|
+
// =============================================================================
|
|
244
|
+
// FLOOR PRICE CALCULATION
|
|
245
|
+
// =============================================================================
|
|
246
|
+
/** Cost-based multiplier for floor price (PHARM, PHARM_FRAC, COST_ML, COST) */
|
|
247
|
+
exports.MIN_PRICE_COST_FACTOR = 0.25;
|
|
248
|
+
/** Cost-based multiplier for floor price (EXT_COST) */
|
|
249
|
+
exports.MIN_PRICE_EXT_COST_FACTOR = 1.0;
|
|
250
|
+
/** Fraction of salePricePVP for recommended minimum price (COMP_SVC) */
|
|
251
|
+
exports.MIN_PRICE_COMP_SVC_SALE_FRACTION = 0.50;
|
|
252
|
+
/** Policies that use cost-based floor price (cost × factor × (1+VAT)) */
|
|
253
|
+
const COST_BASED_FLOOR_POLICIES = [
|
|
254
|
+
PricePolicy.PHARM,
|
|
255
|
+
PricePolicy.PHARM_FRAC,
|
|
256
|
+
PricePolicy.COST_ML,
|
|
257
|
+
PricePolicy.COST,
|
|
258
|
+
];
|
|
259
|
+
/**
|
|
260
|
+
* Calculate floor prices (recommended minimum price and absolute floor) for a catalog item.
|
|
261
|
+
*
|
|
262
|
+
* Business rules by PricePolicy:
|
|
263
|
+
* - PHARM, PHARM_FRAC, COST_ML, COST: both = unitCostBI × 0.25 × (1 + VAT/100), round5
|
|
264
|
+
* - EXT_COST: both = unitCostBI × 1.0 × (1 + VAT/100), round5
|
|
265
|
+
* - COMP_SVC: recommendedMinimumPrice = salePricePVP × 0.50 (round5), floorPrice = 0
|
|
266
|
+
* - NONE, SPECIAL, MANUAL: both null
|
|
267
|
+
*/
|
|
268
|
+
function calculateFloorPrices(params) {
|
|
269
|
+
const { pricePolicy, unitPurchasePriceBI, vatSalePercent, salePricePVP } = params;
|
|
270
|
+
// Cost-based policies (PHARM, PHARM_FRAC, COST_ML, COST)
|
|
271
|
+
if (COST_BASED_FLOOR_POLICIES.includes(pricePolicy)) {
|
|
272
|
+
if (unitPurchasePriceBI <= 0)
|
|
273
|
+
return { recommendedMinimumPrice: null, floorPrice: null };
|
|
274
|
+
const price = roundToNearest5(unitPurchasePriceBI * exports.MIN_PRICE_COST_FACTOR * (1 + vatSalePercent / 100));
|
|
275
|
+
return { recommendedMinimumPrice: price, floorPrice: price };
|
|
276
|
+
}
|
|
277
|
+
// External cost services
|
|
278
|
+
if (pricePolicy === PricePolicy.EXT_COST) {
|
|
279
|
+
if (unitPurchasePriceBI <= 0)
|
|
280
|
+
return { recommendedMinimumPrice: null, floorPrice: null };
|
|
281
|
+
const price = roundToNearest5(unitPurchasePriceBI * exports.MIN_PRICE_EXT_COST_FACTOR * (1 + vatSalePercent / 100));
|
|
282
|
+
return { recommendedMinimumPrice: price, floorPrice: price };
|
|
283
|
+
}
|
|
284
|
+
// Internal services (market-study pricing)
|
|
285
|
+
if (pricePolicy === PricePolicy.COMP_SVC) {
|
|
286
|
+
const minPrice = salePricePVP > 0
|
|
287
|
+
? roundToNearest5(salePricePVP * exports.MIN_PRICE_COMP_SVC_SALE_FRACTION)
|
|
288
|
+
: null;
|
|
289
|
+
return { recommendedMinimumPrice: minPrice, floorPrice: 0 };
|
|
290
|
+
}
|
|
291
|
+
// NONE, SPECIAL, MANUAL — no floor prices
|
|
292
|
+
return { recommendedMinimumPrice: null, floorPrice: null };
|
|
239
293
|
}
|
|
@@ -100,7 +100,6 @@ describe('getMarkupFactor', () => {
|
|
|
100
100
|
});
|
|
101
101
|
it('should return null for policies without a formula', () => {
|
|
102
102
|
expect((0, pricing_constants_1.getMarkupFactor)(pricing_constants_1.PricePolicy.COMP_SVC, pricing_constants_1.PricingTier.HIGH_MARGIN)).toBeNull();
|
|
103
|
-
expect((0, pricing_constants_1.getMarkupFactor)(pricing_constants_1.PricePolicy.TEST, pricing_constants_1.PricingTier.HIGH_MARGIN)).toBeNull();
|
|
104
103
|
expect((0, pricing_constants_1.getMarkupFactor)(pricing_constants_1.PricePolicy.SPECIAL, pricing_constants_1.PricingTier.HIGH_MARGIN)).toBeNull();
|
|
105
104
|
expect((0, pricing_constants_1.getMarkupFactor)(pricing_constants_1.PricePolicy.MANUAL, pricing_constants_1.PricingTier.HIGH_MARGIN)).toBeNull();
|
|
106
105
|
expect((0, pricing_constants_1.getMarkupFactor)(pricing_constants_1.PricePolicy.NONE, pricing_constants_1.PricingTier.HIGH_MARGIN)).toBeNull();
|
|
@@ -265,15 +264,6 @@ describe('calculateRecommendedPricePVP', () => {
|
|
|
265
264
|
});
|
|
266
265
|
expect(result).toBeNull();
|
|
267
266
|
});
|
|
268
|
-
it('should return null for TEST', () => {
|
|
269
|
-
const result = (0, pricing_constants_1.calculateRecommendedPricePVP)({
|
|
270
|
-
pricePolicy: pricing_constants_1.PricePolicy.TEST,
|
|
271
|
-
pricingTier: pricing_constants_1.PricingTier.HIGH_MARGIN,
|
|
272
|
-
unitPurchasePriceBI: 100,
|
|
273
|
-
vatSalePercent: 16,
|
|
274
|
-
});
|
|
275
|
-
expect(result).toBeNull();
|
|
276
|
-
});
|
|
277
267
|
it('should return null for SPECIAL', () => {
|
|
278
268
|
const result = (0, pricing_constants_1.calculateRecommendedPricePVP)({
|
|
279
269
|
pricePolicy: pricing_constants_1.PricePolicy.SPECIAL,
|
|
@@ -322,3 +312,85 @@ describe('calculateRecommendedPricePVP', () => {
|
|
|
322
312
|
expect(result).toBe(60);
|
|
323
313
|
});
|
|
324
314
|
});
|
|
315
|
+
// =============================================================================
|
|
316
|
+
// calculateFloorPrices
|
|
317
|
+
// =============================================================================
|
|
318
|
+
describe('calculateFloorPrices', () => {
|
|
319
|
+
const defaults = { unitPurchasePriceBI: 100, vatSalePercent: 16, salePricePVP: 500 };
|
|
320
|
+
describe('cost-based policies (PHARM, PHARM_FRAC, COST_ML, COST)', () => {
|
|
321
|
+
const costPolicies = [pricing_constants_1.PricePolicy.PHARM, pricing_constants_1.PricePolicy.PHARM_FRAC, pricing_constants_1.PricePolicy.COST_ML, pricing_constants_1.PricePolicy.COST];
|
|
322
|
+
it.each(costPolicies)('%s: both = cost × 0.25 × (1+VAT/100), round5', (policy) => {
|
|
323
|
+
// $100 * 0.25 * 1.16 = $29 → round5 = $30
|
|
324
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: policy });
|
|
325
|
+
expect(result.recommendedMinimumPrice).toBe(30);
|
|
326
|
+
expect(result.floorPrice).toBe(30);
|
|
327
|
+
});
|
|
328
|
+
it('should round to nearest 5', () => {
|
|
329
|
+
// $80 * 0.25 * 1.16 = $23.20 → round5 = $25
|
|
330
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.PHARM, unitPurchasePriceBI: 80 });
|
|
331
|
+
expect(result.recommendedMinimumPrice).toBe(25);
|
|
332
|
+
expect(result.floorPrice).toBe(25);
|
|
333
|
+
});
|
|
334
|
+
it('should return null when cost is 0', () => {
|
|
335
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.PHARM, unitPurchasePriceBI: 0 });
|
|
336
|
+
expect(result.recommendedMinimumPrice).toBeNull();
|
|
337
|
+
expect(result.floorPrice).toBeNull();
|
|
338
|
+
});
|
|
339
|
+
it('should return null when cost is negative', () => {
|
|
340
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COST, unitPurchasePriceBI: -10 });
|
|
341
|
+
expect(result.recommendedMinimumPrice).toBeNull();
|
|
342
|
+
expect(result.floorPrice).toBeNull();
|
|
343
|
+
});
|
|
344
|
+
it('should handle 0% VAT', () => {
|
|
345
|
+
// $100 * 0.25 * 1.0 = $25 → $25
|
|
346
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COST, vatSalePercent: 0 });
|
|
347
|
+
expect(result.recommendedMinimumPrice).toBe(25);
|
|
348
|
+
expect(result.floorPrice).toBe(25);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
describe('EXT_COST', () => {
|
|
352
|
+
it('both = cost × 1.0 × (1+VAT/100), round5', () => {
|
|
353
|
+
// $100 * 1.0 * 1.16 = $116 → round5 = $115
|
|
354
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.EXT_COST });
|
|
355
|
+
expect(result.recommendedMinimumPrice).toBe(115);
|
|
356
|
+
expect(result.floorPrice).toBe(115);
|
|
357
|
+
});
|
|
358
|
+
it('should return null when cost is 0', () => {
|
|
359
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.EXT_COST, unitPurchasePriceBI: 0 });
|
|
360
|
+
expect(result.recommendedMinimumPrice).toBeNull();
|
|
361
|
+
expect(result.floorPrice).toBeNull();
|
|
362
|
+
});
|
|
363
|
+
it('should round to nearest 5', () => {
|
|
364
|
+
// $200 * 1.0 * 1.16 = $232 → round5 = $230
|
|
365
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.EXT_COST, unitPurchasePriceBI: 200 });
|
|
366
|
+
expect(result.recommendedMinimumPrice).toBe(230);
|
|
367
|
+
expect(result.floorPrice).toBe(230);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
describe('COMP_SVC', () => {
|
|
371
|
+
it('recommendedMinimumPrice = salePricePVP × 0.50, floorPrice = 0', () => {
|
|
372
|
+
// $500 * 0.50 = $250 → round5 = $250
|
|
373
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COMP_SVC });
|
|
374
|
+
expect(result.recommendedMinimumPrice).toBe(250);
|
|
375
|
+
expect(result.floorPrice).toBe(0);
|
|
376
|
+
});
|
|
377
|
+
it('should round salePricePVP fraction to nearest 5', () => {
|
|
378
|
+
// $330 * 0.50 = $165 → round5 = $165
|
|
379
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COMP_SVC, salePricePVP: 330 });
|
|
380
|
+
expect(result.recommendedMinimumPrice).toBe(165);
|
|
381
|
+
expect(result.floorPrice).toBe(0);
|
|
382
|
+
});
|
|
383
|
+
it('should return null recommendedMinimumPrice when salePricePVP is 0', () => {
|
|
384
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: pricing_constants_1.PricePolicy.COMP_SVC, salePricePVP: 0 });
|
|
385
|
+
expect(result.recommendedMinimumPrice).toBeNull();
|
|
386
|
+
expect(result.floorPrice).toBe(0);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
describe('no-formula policies (NONE, SPECIAL, MANUAL)', () => {
|
|
390
|
+
it.each([pricing_constants_1.PricePolicy.NONE, pricing_constants_1.PricePolicy.SPECIAL, pricing_constants_1.PricePolicy.MANUAL])('%s: both null', (policy) => {
|
|
391
|
+
const result = (0, pricing_constants_1.calculateFloorPrices)({ ...defaults, pricePolicy: policy });
|
|
392
|
+
expect(result.recommendedMinimumPrice).toBeNull();
|
|
393
|
+
expect(result.floorPrice).toBeNull();
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
});
|
|
@@ -103,6 +103,10 @@ export interface UpdateCatalogItemHvpDataRequest {
|
|
|
103
103
|
pricingTier?: PricingTier;
|
|
104
104
|
/** Recommended price PVP (calculated from policy + tier + cost) */
|
|
105
105
|
recommendedPrice?: number;
|
|
106
|
+
/** Recommended minimum price PVP (calculated from policy + cost) */
|
|
107
|
+
recommendedMinimumPrice?: number;
|
|
108
|
+
/** Floor price PVP (calculated from policy + cost) */
|
|
109
|
+
floorPrice?: number;
|
|
106
110
|
/** How stock levels are managed */
|
|
107
111
|
stockPolicy?: StockPolicy;
|
|
108
112
|
/** Observations generated by analysis script */
|
|
@@ -135,6 +135,10 @@ export interface CatalogItemDetailResponse {
|
|
|
135
135
|
* Calculated from: unitCostBI * markupFactor * (1 + VAT/100)
|
|
136
136
|
*/
|
|
137
137
|
recommendedPrice?: number;
|
|
138
|
+
/** Precio mínimo recomendado PVP (con IVA) — suggested QVET "tarifa mínima" */
|
|
139
|
+
recommendedMinimumPrice?: number;
|
|
140
|
+
/** Precio piso PVP (con IVA) — absolute minimum, never sell below this */
|
|
141
|
+
floorPrice?: number;
|
|
138
142
|
/** How stock levels are managed */
|
|
139
143
|
stockPolicy?: StockPolicy;
|
|
140
144
|
/** Observations generated by analysis script */
|