hvp-shared 3.8.0 → 4.2.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.
@@ -5,6 +5,8 @@ export * from './mexican-states';
5
5
  export * from './sat-catalogs';
6
6
  export * from './collaborator.constants';
7
7
  export * from './catalog-item.constants';
8
+ export * from './market-competition.constants';
9
+ export * from './pricing-rule.constants';
8
10
  export * from './qvet-catalog';
9
11
  export * from './qvet-warehouses';
10
12
  export * from './qvet-inventory';
@@ -21,6 +21,8 @@ __exportStar(require("./mexican-states"), exports);
21
21
  __exportStar(require("./sat-catalogs"), exports);
22
22
  __exportStar(require("./collaborator.constants"), exports);
23
23
  __exportStar(require("./catalog-item.constants"), exports);
24
+ __exportStar(require("./market-competition.constants"), exports);
25
+ __exportStar(require("./pricing-rule.constants"), exports);
24
26
  __exportStar(require("./qvet-catalog"), exports);
25
27
  __exportStar(require("./qvet-warehouses"), exports);
26
28
  __exportStar(require("./qvet-inventory"), exports);
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Market Competition Level
3
+ *
4
+ * Indicates the level of market competition for a product/service.
5
+ * Used to determine pricing strategy and target margins.
6
+ */
7
+ export declare enum MarketCompetition {
8
+ HIGH = "high",
9
+ MEDIUM = "medium",
10
+ LOW = "low"
11
+ }
12
+ /**
13
+ * Spanish labels for MarketCompetition
14
+ */
15
+ export declare const MARKET_COMPETITION_LABELS: Record<MarketCompetition, string>;
16
+ /**
17
+ * All market competition values as array (for dropdowns)
18
+ */
19
+ export declare const MARKET_COMPETITION_VALUES: MarketCompetition[];
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MARKET_COMPETITION_VALUES = exports.MARKET_COMPETITION_LABELS = exports.MarketCompetition = void 0;
4
+ /**
5
+ * Market Competition Level
6
+ *
7
+ * Indicates the level of market competition for a product/service.
8
+ * Used to determine pricing strategy and target margins.
9
+ */
10
+ var MarketCompetition;
11
+ (function (MarketCompetition) {
12
+ MarketCompetition["HIGH"] = "high";
13
+ MarketCompetition["MEDIUM"] = "medium";
14
+ MarketCompetition["LOW"] = "low";
15
+ })(MarketCompetition || (exports.MarketCompetition = MarketCompetition = {}));
16
+ /**
17
+ * Spanish labels for MarketCompetition
18
+ */
19
+ exports.MARKET_COMPETITION_LABELS = {
20
+ [MarketCompetition.HIGH]: 'Competencia Alta',
21
+ [MarketCompetition.MEDIUM]: 'Competencia Media',
22
+ [MarketCompetition.LOW]: 'Competencia Baja',
23
+ };
24
+ /**
25
+ * All market competition values as array (for dropdowns)
26
+ */
27
+ exports.MARKET_COMPETITION_VALUES = Object.values(MarketCompetition);
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Pricing Rule System
3
+ *
4
+ * Codes and target margins for pricing strategy.
5
+ * Each product can be assigned a pricing rule that determines its target margin.
6
+ */
7
+ /**
8
+ * Pricing Rule Codes (3-letter abbreviations)
9
+ */
10
+ export declare enum PricingRuleCode {
11
+ ECA = "ECA",// External Commission Alto - 40%
12
+ ECM = "ECM",// External Commission Medio - 70%
13
+ ECB = "ECB",// External Commission Bajo - 100%
14
+ ESA = "ESA",// External Sin-comision Alto - 50%
15
+ ESM = "ESM",// External Sin-comision Medio - 75%
16
+ ESB = "ESB",// External Sin-comision Bajo - 100%
17
+ FRA = "FRA",// Fraccionada Alta - 100%
18
+ FRM = "FRM",// Fraccionada Media - 150%
19
+ FRB = "FRB",// Fraccionada Baja - 200%
20
+ MGA = "MGA",// ML Grande Alta - 400%
21
+ MGB = "MGB",// ML Grande Baja/Media - 800%
22
+ MPA = "MPA",// ML Pequeño Alta - 150%
23
+ MPB = "MPB",// ML Pequeño Baja/Media - 250%
24
+ POA = "POA",// Presentación Original Alta - 33.33%
25
+ POM = "POM",// Presentación Original Media - 66.67%
26
+ POB = "POB",// Presentación Original Baja - 100%
27
+ XPA = "XPA",// Productos caros - 100%
28
+ XPM = "XPM",// Productos precio medio (<$500) - 200%
29
+ XPB = "XPB",// Productos baratos (<$25) - 400%
30
+ TUS = "TUS",// Tests de Un Solo uso - 150%
31
+ RGL = "RGL",// Regla General - 100%
32
+ PRE = "PRE",// Precio Específico (manual) - 0%
33
+ NRA = "NRA"
34
+ }
35
+ /**
36
+ * Pricing Rule Categories for grouping in UI
37
+ */
38
+ export type PricingRuleCategory = 'external_commission' | 'external_no_commission' | 'fractioned' | 'fractioned_ml_large' | 'fractioned_ml_small' | 'original' | 'price_range' | 'special' | 'control';
39
+ /**
40
+ * Category labels in Spanish
41
+ */
42
+ export declare const PRICING_RULE_CATEGORY_LABELS: Record<PricingRuleCategory, string>;
43
+ /**
44
+ * Pricing Rule Information
45
+ */
46
+ export interface PricingRuleInfo {
47
+ code: PricingRuleCode;
48
+ label: string;
49
+ targetMargin: number;
50
+ category: PricingRuleCategory;
51
+ }
52
+ /**
53
+ * Complete pricing rules map
54
+ */
55
+ export declare const PRICING_RULES: Record<PricingRuleCode, PricingRuleInfo>;
56
+ /**
57
+ * Get pricing rules grouped by category (for UI dropdowns)
58
+ */
59
+ export declare function getPricingRulesByCategory(): Record<PricingRuleCategory, PricingRuleInfo[]>;
60
+ /**
61
+ * Get pricing rule info by code
62
+ */
63
+ export declare function getPricingRuleInfo(code: PricingRuleCode): PricingRuleInfo;
64
+ /**
65
+ * All pricing rule codes as array
66
+ */
67
+ export declare const PRICING_RULE_CODES: PricingRuleCode[];
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ /**
3
+ * Pricing Rule System
4
+ *
5
+ * Codes and target margins for pricing strategy.
6
+ * Each product can be assigned a pricing rule that determines its target margin.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PRICING_RULE_CODES = exports.PRICING_RULES = exports.PRICING_RULE_CATEGORY_LABELS = exports.PricingRuleCode = void 0;
10
+ exports.getPricingRulesByCategory = getPricingRulesByCategory;
11
+ exports.getPricingRuleInfo = getPricingRuleInfo;
12
+ /**
13
+ * Pricing Rule Codes (3-letter abbreviations)
14
+ */
15
+ var PricingRuleCode;
16
+ (function (PricingRuleCode) {
17
+ // Servicios externos CON comisión
18
+ PricingRuleCode["ECA"] = "ECA";
19
+ PricingRuleCode["ECM"] = "ECM";
20
+ PricingRuleCode["ECB"] = "ECB";
21
+ // Servicios externos SIN comisión
22
+ PricingRuleCode["ESA"] = "ESA";
23
+ PricingRuleCode["ESM"] = "ESM";
24
+ PricingRuleCode["ESB"] = "ESB";
25
+ // Venta fraccionada de productos
26
+ PricingRuleCode["FRA"] = "FRA";
27
+ PricingRuleCode["FRM"] = "FRM";
28
+ PricingRuleCode["FRB"] = "FRB";
29
+ // Venta fraccionada de ml de frascos GRANDES
30
+ PricingRuleCode["MGA"] = "MGA";
31
+ PricingRuleCode["MGB"] = "MGB";
32
+ // Venta fraccionada de ml de frascos PEQUEÑOS
33
+ PricingRuleCode["MPA"] = "MPA";
34
+ PricingRuleCode["MPB"] = "MPB";
35
+ // Venta en presentación original
36
+ PricingRuleCode["POA"] = "POA";
37
+ PricingRuleCode["POM"] = "POM";
38
+ PricingRuleCode["POB"] = "POB";
39
+ // Reglas por rango de precio
40
+ PricingRuleCode["XPA"] = "XPA";
41
+ PricingRuleCode["XPM"] = "XPM";
42
+ PricingRuleCode["XPB"] = "XPB";
43
+ // Especiales
44
+ PricingRuleCode["TUS"] = "TUS";
45
+ PricingRuleCode["RGL"] = "RGL";
46
+ // Control
47
+ PricingRuleCode["PRE"] = "PRE";
48
+ PricingRuleCode["NRA"] = "NRA";
49
+ })(PricingRuleCode || (exports.PricingRuleCode = PricingRuleCode = {}));
50
+ /**
51
+ * Category labels in Spanish
52
+ */
53
+ exports.PRICING_RULE_CATEGORY_LABELS = {
54
+ external_commission: 'Servicios externos con comisión',
55
+ external_no_commission: 'Servicios externos sin comisión',
56
+ fractioned: 'Venta fraccionada de productos',
57
+ fractioned_ml_large: 'Venta fraccionada ml frascos grandes',
58
+ fractioned_ml_small: 'Venta fraccionada ml frascos pequeños',
59
+ original: 'Venta en presentación original',
60
+ price_range: 'Por rango de precio',
61
+ special: 'Reglas especiales',
62
+ control: 'Control',
63
+ };
64
+ /**
65
+ * Complete pricing rules map
66
+ */
67
+ exports.PRICING_RULES = {
68
+ // Servicios externos CON comisión
69
+ [PricingRuleCode.ECA]: {
70
+ code: PricingRuleCode.ECA,
71
+ label: 'Servicios externos con comisión de precio alto',
72
+ targetMargin: 40,
73
+ category: 'external_commission',
74
+ },
75
+ [PricingRuleCode.ECM]: {
76
+ code: PricingRuleCode.ECM,
77
+ label: 'Servicios externos con comisión de precio medio',
78
+ targetMargin: 70,
79
+ category: 'external_commission',
80
+ },
81
+ [PricingRuleCode.ECB]: {
82
+ code: PricingRuleCode.ECB,
83
+ label: 'Servicios externos con comisión de precio bajo',
84
+ targetMargin: 100,
85
+ category: 'external_commission',
86
+ },
87
+ // Servicios externos SIN comisión
88
+ [PricingRuleCode.ESA]: {
89
+ code: PricingRuleCode.ESA,
90
+ label: 'Servicios externos sin comisión de precio alto',
91
+ targetMargin: 50,
92
+ category: 'external_no_commission',
93
+ },
94
+ [PricingRuleCode.ESM]: {
95
+ code: PricingRuleCode.ESM,
96
+ label: 'Servicios externos sin comisión de precio medio',
97
+ targetMargin: 75,
98
+ category: 'external_no_commission',
99
+ },
100
+ [PricingRuleCode.ESB]: {
101
+ code: PricingRuleCode.ESB,
102
+ label: 'Servicios externos sin comisión de precio bajo',
103
+ targetMargin: 100,
104
+ category: 'external_no_commission',
105
+ },
106
+ // Venta fraccionada de productos
107
+ [PricingRuleCode.FRA]: {
108
+ code: PricingRuleCode.FRA,
109
+ label: 'Venta fraccionada de productos competencia alta',
110
+ targetMargin: 100,
111
+ category: 'fractioned',
112
+ },
113
+ [PricingRuleCode.FRM]: {
114
+ code: PricingRuleCode.FRM,
115
+ label: 'Venta fraccionada de productos competencia media',
116
+ targetMargin: 150,
117
+ category: 'fractioned',
118
+ },
119
+ [PricingRuleCode.FRB]: {
120
+ code: PricingRuleCode.FRB,
121
+ label: 'Venta fraccionada de productos competencia baja',
122
+ targetMargin: 200,
123
+ category: 'fractioned',
124
+ },
125
+ // Venta fraccionada de ml de frascos GRANDES
126
+ [PricingRuleCode.MGA]: {
127
+ code: PricingRuleCode.MGA,
128
+ label: 'Venta fraccionada de ml de frascos grandes competencia alta',
129
+ targetMargin: 400,
130
+ category: 'fractioned_ml_large',
131
+ },
132
+ [PricingRuleCode.MGB]: {
133
+ code: PricingRuleCode.MGB,
134
+ label: 'Venta fraccionada de ml de frascos grandes competencia baja o media',
135
+ targetMargin: 800,
136
+ category: 'fractioned_ml_large',
137
+ },
138
+ // Venta fraccionada de ml de frascos PEQUEÑOS
139
+ [PricingRuleCode.MPA]: {
140
+ code: PricingRuleCode.MPA,
141
+ label: 'Venta fraccionada de ml de frascos pequeños competencia alta',
142
+ targetMargin: 150,
143
+ category: 'fractioned_ml_small',
144
+ },
145
+ [PricingRuleCode.MPB]: {
146
+ code: PricingRuleCode.MPB,
147
+ label: 'Venta fraccionada de ml de frascos pequeños competencia baja o media',
148
+ targetMargin: 250,
149
+ category: 'fractioned_ml_small',
150
+ },
151
+ // Venta en presentación original
152
+ [PricingRuleCode.POA]: {
153
+ code: PricingRuleCode.POA,
154
+ label: 'Venta en presentación original productos competencia alta',
155
+ targetMargin: 33.33,
156
+ category: 'original',
157
+ },
158
+ [PricingRuleCode.POM]: {
159
+ code: PricingRuleCode.POM,
160
+ label: 'Venta en presentación original productos competencia media',
161
+ targetMargin: 66.67,
162
+ category: 'original',
163
+ },
164
+ [PricingRuleCode.POB]: {
165
+ code: PricingRuleCode.POB,
166
+ label: 'Venta en presentación original productos competencia baja',
167
+ targetMargin: 100,
168
+ category: 'original',
169
+ },
170
+ // Reglas por rango de precio
171
+ [PricingRuleCode.XPA]: {
172
+ code: PricingRuleCode.XPA,
173
+ label: 'Venta de productos caros',
174
+ targetMargin: 100,
175
+ category: 'price_range',
176
+ },
177
+ [PricingRuleCode.XPM]: {
178
+ code: PricingRuleCode.XPM,
179
+ label: 'Venta de productos de precio medio (<$500)',
180
+ targetMargin: 200,
181
+ category: 'price_range',
182
+ },
183
+ [PricingRuleCode.XPB]: {
184
+ code: PricingRuleCode.XPB,
185
+ label: 'Venta de productos baratos (<$25)',
186
+ targetMargin: 400,
187
+ category: 'price_range',
188
+ },
189
+ // Especiales
190
+ [PricingRuleCode.TUS]: {
191
+ code: PricingRuleCode.TUS,
192
+ label: 'Los precios de tests de un solo uso (ej. CANIV-4)',
193
+ targetMargin: 150,
194
+ category: 'special',
195
+ },
196
+ [PricingRuleCode.RGL]: {
197
+ code: PricingRuleCode.RGL,
198
+ label: 'Regla general',
199
+ targetMargin: 100,
200
+ category: 'special',
201
+ },
202
+ // Control
203
+ [PricingRuleCode.PRE]: {
204
+ code: PricingRuleCode.PRE,
205
+ label: 'Precio específico',
206
+ targetMargin: 0,
207
+ category: 'control',
208
+ },
209
+ [PricingRuleCode.NRA]: {
210
+ code: PricingRuleCode.NRA,
211
+ label: 'Exclusión reglas',
212
+ targetMargin: 0,
213
+ category: 'control',
214
+ },
215
+ };
216
+ /**
217
+ * Get pricing rules grouped by category (for UI dropdowns)
218
+ */
219
+ function getPricingRulesByCategory() {
220
+ const grouped = {
221
+ external_commission: [],
222
+ external_no_commission: [],
223
+ fractioned: [],
224
+ fractioned_ml_large: [],
225
+ fractioned_ml_small: [],
226
+ original: [],
227
+ price_range: [],
228
+ special: [],
229
+ control: [],
230
+ };
231
+ Object.values(exports.PRICING_RULES).forEach((rule) => {
232
+ grouped[rule.category].push(rule);
233
+ });
234
+ return grouped;
235
+ }
236
+ /**
237
+ * Get pricing rule info by code
238
+ */
239
+ function getPricingRuleInfo(code) {
240
+ return exports.PRICING_RULES[code];
241
+ }
242
+ /**
243
+ * All pricing rule codes as array
244
+ */
245
+ exports.PRICING_RULE_CODES = Object.values(PricingRuleCode);
@@ -41,10 +41,10 @@ export interface CatalogItemQueryFilters {
41
41
  export interface UpdateCatalogItemRequest {
42
42
  /** Update description (sets pending) */
43
43
  description?: string;
44
- /** Update sale price (sets pending) */
45
- salePrice?: number;
46
- /** Update purchase price (sets pending) */
47
- purchasePrice?: number;
44
+ /** Update sale price PVP - con IVA (sets pending) */
45
+ salePricePVP?: number;
46
+ /** Update purchase price BI - sin IVA (sets pending) */
47
+ purchasePriceBI?: number;
48
48
  /** Update section (sets pending) */
49
49
  section?: string;
50
50
  /** Update family (sets pending) */
@@ -5,6 +5,8 @@
5
5
  */
6
6
  import { SyncField } from '../../types/sync-field.types';
7
7
  import { UsageType, SyncStatus } from '../../constants/catalog-item.constants';
8
+ import { MarketCompetition } from '../../constants/market-competition.constants';
9
+ import { PricingRuleCode } from '../../constants/pricing-rule.constants';
8
10
  import { Warehouse } from '../../types/qvet.types';
9
11
  /**
10
12
  * Warehouse stock response
@@ -14,6 +16,8 @@ export interface WarehouseStockResponse {
14
16
  currentStock: number;
15
17
  minStock: SyncField<number>;
16
18
  optimalStock: SyncField<number>;
19
+ /** Próxima fecha de caducidad en este almacén */
20
+ nextExpirationDate?: string;
17
21
  }
18
22
  /**
19
23
  * CatalogItem List Response
@@ -28,8 +32,10 @@ export interface CatalogItemListResponse {
28
32
  description: string;
29
33
  section: string;
30
34
  family: string;
31
- salePrice: number;
32
- minimumPrice: number;
35
+ /** Precio venta PVP (con IVA) */
36
+ salePricePVP: number;
37
+ /** Precio mínimo PVP (con IVA) */
38
+ minimumPricePVP: number;
33
39
  isActive: boolean;
34
40
  usageType: UsageType;
35
41
  hasPendingChanges: boolean;
@@ -56,15 +62,49 @@ export interface CatalogItemDetailResponse {
56
62
  family: SyncField<string>;
57
63
  subfamily: SyncField<string>;
58
64
  brand: SyncField<string>;
59
- purchasePrice: SyncField<number>;
60
- salePrice: SyncField<number>;
61
- minimumPrice: SyncField<number>;
62
- purchaseMargin: SyncField<number>;
63
- saleMargin: SyncField<number>;
64
- /** Calculated: purchasePrice / conversionFactor (price per sale unit) */
65
- unitPurchasePrice: number;
65
+ /** Precio compra por unidad de compra - Base Imponible (sin IVA) */
66
+ purchasePriceBI: SyncField<number>;
67
+ /** Precio venta por unidad de venta - PVP (con IVA) */
68
+ salePricePVP: SyncField<number>;
69
+ /** Precio mínimo por unidad de venta - PVP (con IVA) */
70
+ minimumPricePVP: SyncField<number>;
71
+ /** IVA venta (%) - ej: 16 */
66
72
  vatSale: SyncField<number>;
73
+ /** IVA compra (%) - ej: 16 */
67
74
  vatPurchase: SyncField<number>;
75
+ /** Precio compra unitario BI = purchasePriceBI / conversionFactor */
76
+ unitPurchasePriceBI: number;
77
+ /** Precio venta sin IVA = salePricePVP / (1 + vatSale/100) */
78
+ salePriceBI: number;
79
+ /** Precio mínimo sin IVA = minimumPricePVP / (1 + vatSale/100) */
80
+ minimumPriceBI: number;
81
+ /** Margen QVET (incorrecto, mezcla BI y PVP) - solo referencia */
82
+ qvetPurchaseMargin: SyncField<number>;
83
+ qvetSaleMargin: SyncField<number>;
84
+ /**
85
+ * Margen de Compra (Markup) - Precio Venta
86
+ * Formula: (salePriceBI - unitPurchasePriceBI) / unitPurchasePriceBI * 100
87
+ * Mide: Rentabilidad sobre lo invertido (cuánto ganas sobre lo que pagaste)
88
+ */
89
+ marginSale: number;
90
+ /**
91
+ * Margen de Venta (Profit Margin) - Precio Venta
92
+ * Formula: (salePriceBI - unitPurchasePriceBI) / salePriceBI * 100
93
+ * Mide: Qué porcentaje del precio de venta es ganancia
94
+ */
95
+ profitMarginSale: number;
96
+ /**
97
+ * Margen de Compra (Markup) - Precio Mínimo
98
+ * Formula: (minimumPriceBI - unitPurchasePriceBI) / unitPurchasePriceBI * 100
99
+ * Mide: Rentabilidad sobre lo invertido
100
+ */
101
+ marginMinimum: number;
102
+ /**
103
+ * Margen de Venta (Profit Margin) - Precio Mínimo
104
+ * Formula: (minimumPriceBI - unitPurchasePriceBI) / minimumPriceBI * 100
105
+ * Mide: Qué porcentaje del precio mínimo es ganancia
106
+ */
107
+ profitMarginMinimum: number;
68
108
  purchaseUnit: SyncField<string>;
69
109
  saleUnit: SyncField<string>;
70
110
  conversionFactor: SyncField<number>;
@@ -73,8 +113,11 @@ export interface CatalogItemDetailResponse {
73
113
  stockByWarehouse: WarehouseStockResponse[];
74
114
  observations: SyncField<string>;
75
115
  description2: SyncField<string>;
76
- visibleInSales: SyncField<string>;
77
- visibleInPurchases: SyncField<string>;
116
+ /** Visible en ventas (convertido de "S"/"N" a boolean) */
117
+ visibleInSales: SyncField<boolean>;
118
+ /** Visible en compras (convertido de "S"/"N" a boolean) */
119
+ visibleInPurchases: SyncField<boolean>;
120
+ /** Centros donde es visible (ej: "URBAN, HARBOR, MONTEJO") */
78
121
  visibleIn: SyncField<string>;
79
122
  qvetCreatedAt?: string;
80
123
  lastSaleDate?: string;
@@ -84,6 +127,15 @@ export interface CatalogItemDetailResponse {
84
127
  usageType: UsageType;
85
128
  notes?: string;
86
129
  internalCategory?: string;
130
+ /** Nivel de competencia en el mercado */
131
+ marketCompetition?: MarketCompetition;
132
+ /** Código de regla de precio - determines target margin */
133
+ pricingRuleCode?: PricingRuleCode;
134
+ /**
135
+ * Precio recomendado (PVP con IVA)
136
+ * Calculated from: cost * (1 + targetMargin/100) * (1 + VAT/100)
137
+ */
138
+ recommendedPrice?: number;
87
139
  };
88
140
  hasPendingChanges: boolean;
89
141
  lastSyncAt: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hvp-shared",
3
- "version": "3.8.0",
3
+ "version": "4.2.0",
4
4
  "description": "Shared types and utilities for HVP backend and frontend",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",