@cimplify/sdk 0.1.0 → 0.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.
package/dist/index.mjs CHANGED
@@ -1302,23 +1302,354 @@ function query(entity) {
1302
1302
  return new QueryBuilder(entity);
1303
1303
  }
1304
1304
 
1305
- // src/utils/payment.ts
1305
+ // src/utils/price.ts
1306
1306
  var CURRENCY_SYMBOLS = {
1307
- GHS: "GH\u20B5",
1307
+ // Major world currencies
1308
1308
  USD: "$",
1309
1309
  EUR: "\u20AC",
1310
1310
  GBP: "\xA3",
1311
+ JPY: "\xA5",
1312
+ CNY: "\xA5",
1313
+ CHF: "CHF",
1314
+ CAD: "C$",
1315
+ AUD: "A$",
1316
+ NZD: "NZ$",
1317
+ HKD: "HK$",
1318
+ SGD: "S$",
1319
+ INR: "\u20B9",
1320
+ BRL: "R$",
1321
+ MXN: "MX$",
1322
+ KRW: "\u20A9",
1323
+ RUB: "\u20BD",
1324
+ TRY: "\u20BA",
1325
+ THB: "\u0E3F",
1326
+ PLN: "z\u0142",
1327
+ SEK: "kr",
1328
+ NOK: "kr",
1329
+ DKK: "kr",
1330
+ CZK: "K\u010D",
1331
+ HUF: "Ft",
1332
+ ILS: "\u20AA",
1333
+ AED: "\u062F.\u0625",
1334
+ SAR: "\uFDFC",
1335
+ MYR: "RM",
1336
+ PHP: "\u20B1",
1337
+ IDR: "Rp",
1338
+ VND: "\u20AB",
1339
+ TWD: "NT$",
1340
+ // African currencies
1341
+ GHS: "GH\u20B5",
1311
1342
  NGN: "\u20A6",
1312
1343
  KES: "KSh",
1313
1344
  ZAR: "R",
1314
1345
  XOF: "CFA",
1315
- XAF: "FCFA"
1346
+ XAF: "FCFA",
1347
+ EGP: "E\xA3",
1348
+ MAD: "MAD",
1349
+ TZS: "TSh",
1350
+ UGX: "USh",
1351
+ RWF: "FRw",
1352
+ ETB: "Br",
1353
+ ZMW: "ZK",
1354
+ BWP: "P",
1355
+ MUR: "\u20A8",
1356
+ SCR: "\u20A8",
1357
+ NAD: "N$",
1358
+ SZL: "E",
1359
+ LSL: "L",
1360
+ MWK: "MK",
1361
+ AOA: "Kz",
1362
+ CDF: "FC",
1363
+ GMD: "D",
1364
+ GNF: "FG",
1365
+ LRD: "L$",
1366
+ SLL: "Le",
1367
+ MZN: "MT",
1368
+ SDG: "SDG",
1369
+ SSP: "SSP",
1370
+ SOS: "Sh.So.",
1371
+ DJF: "Fdj",
1372
+ ERN: "Nfk",
1373
+ CVE: "$",
1374
+ STN: "Db",
1375
+ KMF: "CF",
1376
+ BIF: "FBu"
1316
1377
  };
1378
+ function getCurrencySymbol(currencyCode) {
1379
+ return CURRENCY_SYMBOLS[currencyCode.toUpperCase()] || currencyCode;
1380
+ }
1381
+ function formatNumberCompact(value, decimals = 1) {
1382
+ const absValue = Math.abs(value);
1383
+ const sign = value < 0 ? "-" : "";
1384
+ if (absValue >= 1e9) {
1385
+ return `${sign}${(absValue / 1e9).toFixed(decimals)}B`;
1386
+ }
1387
+ if (absValue >= 1e6) {
1388
+ return `${sign}${(absValue / 1e6).toFixed(decimals)}M`;
1389
+ }
1390
+ if (absValue >= 1e3) {
1391
+ return `${sign}${(absValue / 1e3).toFixed(decimals)}K`;
1392
+ }
1393
+ return `${sign}${absValue.toFixed(decimals)}`;
1394
+ }
1395
+ function formatPrice(amount, currency = "GHS", locale = "en-US") {
1396
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1397
+ if (isNaN(numAmount)) {
1398
+ return `${getCurrencySymbol(currency)}0.00`;
1399
+ }
1400
+ try {
1401
+ return new Intl.NumberFormat(locale, {
1402
+ style: "currency",
1403
+ currency: currency.toUpperCase(),
1404
+ minimumFractionDigits: 2,
1405
+ maximumFractionDigits: 2
1406
+ }).format(numAmount);
1407
+ } catch {
1408
+ return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
1409
+ }
1410
+ }
1411
+ function formatPriceAdjustment(amount, currency = "GHS", locale = "en-US") {
1412
+ const formatted = formatPrice(Math.abs(amount), currency, locale);
1413
+ if (amount > 0) {
1414
+ return `+${formatted}`;
1415
+ } else if (amount < 0) {
1416
+ return `-${formatted}`;
1417
+ }
1418
+ return formatted;
1419
+ }
1420
+ function formatPriceCompact(amount, currency = "GHS", decimals = 1) {
1421
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1422
+ if (isNaN(numAmount)) {
1423
+ return `${getCurrencySymbol(currency)}0`;
1424
+ }
1425
+ const symbol = getCurrencySymbol(currency);
1426
+ if (Math.abs(numAmount) < 1e3) {
1427
+ return `${symbol}${numAmount.toFixed(2)}`;
1428
+ }
1429
+ return `${symbol}${formatNumberCompact(numAmount, decimals)}`;
1430
+ }
1317
1431
  function formatMoney(amount, currency = "GHS") {
1318
- const symbol = CURRENCY_SYMBOLS[currency.toUpperCase()] || currency;
1432
+ const symbol = getCurrencySymbol(currency);
1319
1433
  const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1434
+ if (isNaN(numAmount)) {
1435
+ return `${symbol}0.00`;
1436
+ }
1320
1437
  return `${symbol}${numAmount.toFixed(2)}`;
1321
1438
  }
1439
+ function parsePrice(value) {
1440
+ if (value === void 0 || value === null) {
1441
+ return 0;
1442
+ }
1443
+ if (typeof value === "number") {
1444
+ return isNaN(value) ? 0 : value;
1445
+ }
1446
+ const cleaned = value.replace(/[^\d.-]/g, "");
1447
+ const parsed = parseFloat(cleaned);
1448
+ return isNaN(parsed) ? 0 : parsed;
1449
+ }
1450
+ function parseTaxInfo(taxInfoStr) {
1451
+ try {
1452
+ const parts = taxInfoStr.split(":");
1453
+ if (parts.length < 4 || parts[0] !== "T") {
1454
+ return void 0;
1455
+ }
1456
+ const taxRate = parseFloat(parts[1]);
1457
+ const taxAmount = parseFloat(parts[2]);
1458
+ const isInclusive = parts[3] === "I";
1459
+ const components = [];
1460
+ if (parts.length > 4 && parts[4]) {
1461
+ const componentPairs = parts[4].split(",");
1462
+ for (const pair of componentPairs) {
1463
+ const [name, rateStr] = pair.split(":");
1464
+ if (name && rateStr) {
1465
+ components.push({
1466
+ name: name.trim(),
1467
+ rate: parseFloat(rateStr)
1468
+ });
1469
+ }
1470
+ }
1471
+ }
1472
+ return {
1473
+ taxRate,
1474
+ taxAmount,
1475
+ isInclusive,
1476
+ components
1477
+ };
1478
+ } catch {
1479
+ return void 0;
1480
+ }
1481
+ }
1482
+ function parsePricePath(signedPricePath) {
1483
+ if (!signedPricePath) {
1484
+ return {
1485
+ basePrice: 0,
1486
+ finalPrice: 0,
1487
+ currency: "GHS",
1488
+ decisionPath: "",
1489
+ isValid: false,
1490
+ isExpired: false
1491
+ };
1492
+ }
1493
+ try {
1494
+ const parts = signedPricePath.split("\xA7");
1495
+ if (parts.length !== 3) {
1496
+ return {
1497
+ basePrice: 0,
1498
+ finalPrice: 0,
1499
+ currency: "GHS",
1500
+ decisionPath: "",
1501
+ isValid: false,
1502
+ isExpired: false
1503
+ };
1504
+ }
1505
+ const [pricePath, expiryStr, signature] = parts;
1506
+ const expiryTimestamp = parseInt(expiryStr, 10);
1507
+ const now = Math.floor(Date.now() / 1e3);
1508
+ const isExpired = now > expiryTimestamp;
1509
+ const priceComponents = pricePath.split("|");
1510
+ if (priceComponents.length < 5) {
1511
+ return {
1512
+ basePrice: 0,
1513
+ finalPrice: 0,
1514
+ currency: "GHS",
1515
+ decisionPath: "",
1516
+ isValid: false,
1517
+ isExpired
1518
+ };
1519
+ }
1520
+ const basePrice = parseFloat(priceComponents[0]);
1521
+ const finalPrice = parseFloat(priceComponents[1]);
1522
+ const currency = priceComponents[2];
1523
+ const taxInfoStr = priceComponents[3];
1524
+ const decisionPath = priceComponents.slice(4).join("|");
1525
+ let taxInfo;
1526
+ if (taxInfoStr && taxInfoStr.startsWith("T:")) {
1527
+ taxInfo = parseTaxInfo(taxInfoStr);
1528
+ } else if (taxInfoStr === "0" || !taxInfoStr) {
1529
+ taxInfo = {
1530
+ taxRate: 0,
1531
+ taxAmount: 0,
1532
+ isInclusive: false,
1533
+ components: []
1534
+ };
1535
+ }
1536
+ let markupPercentage;
1537
+ let markupAmount;
1538
+ let discountPercentage;
1539
+ if (decisionPath) {
1540
+ const pathParts = decisionPath.split(":");
1541
+ if (pathParts.length > 1 && pathParts[1]) {
1542
+ const adjustments = pathParts[1].split(",");
1543
+ for (const adj of adjustments) {
1544
+ const adjParts = adj.split("|");
1545
+ if (adjParts[0] && adjParts[0].startsWith("ch")) {
1546
+ markupAmount = parseFloat(adjParts[1]) || 0;
1547
+ markupPercentage = parseFloat(adjParts[2]) || 0;
1548
+ break;
1549
+ }
1550
+ }
1551
+ }
1552
+ }
1553
+ if (markupAmount === void 0 && finalPrice > basePrice) {
1554
+ markupAmount = finalPrice - basePrice;
1555
+ markupPercentage = basePrice > 0 ? markupAmount / basePrice * 100 : 0;
1556
+ } else if (basePrice > finalPrice) {
1557
+ discountPercentage = basePrice > 0 ? (basePrice - finalPrice) / basePrice * 100 : 0;
1558
+ }
1559
+ return {
1560
+ basePrice,
1561
+ finalPrice,
1562
+ currency,
1563
+ decisionPath,
1564
+ discountPercentage,
1565
+ markupPercentage,
1566
+ markupAmount,
1567
+ taxInfo,
1568
+ isValid: !isExpired && signature.length > 0,
1569
+ isExpired,
1570
+ expiryTimestamp
1571
+ };
1572
+ } catch {
1573
+ return {
1574
+ basePrice: 0,
1575
+ finalPrice: 0,
1576
+ currency: "GHS",
1577
+ decisionPath: "",
1578
+ isValid: false,
1579
+ isExpired: false
1580
+ };
1581
+ }
1582
+ }
1583
+ function parsedPriceToPriceInfo(parsedPrice) {
1584
+ return {
1585
+ base_price: parsedPrice.basePrice,
1586
+ final_price: parsedPrice.finalPrice,
1587
+ markup_percentage: parsedPrice.markupPercentage,
1588
+ markup_amount: parsedPrice.markupAmount,
1589
+ currency: parsedPrice.currency,
1590
+ tax_info: parsedPrice.taxInfo,
1591
+ decision_path: parsedPrice.decisionPath
1592
+ };
1593
+ }
1594
+ function extractPriceInfo(signedPricePath) {
1595
+ const parsed = parsePricePath(signedPricePath);
1596
+ return parsedPriceToPriceInfo(parsed);
1597
+ }
1598
+ function getDisplayPrice(product) {
1599
+ if (product.price_path) {
1600
+ const priceInfo = extractPriceInfo(product.price_path);
1601
+ return priceInfo.final_price;
1602
+ } else if (product.price_info) {
1603
+ return product.price_info.final_price;
1604
+ }
1605
+ return 0;
1606
+ }
1607
+ function getBasePrice(product) {
1608
+ if (product.price_path) {
1609
+ const priceInfo = extractPriceInfo(product.price_path);
1610
+ return priceInfo.base_price;
1611
+ } else if (product.price_info) {
1612
+ return product.price_info.base_price;
1613
+ }
1614
+ return 0;
1615
+ }
1616
+ function isOnSale(product) {
1617
+ const basePrice = getBasePrice(product);
1618
+ const finalPrice = getDisplayPrice(product);
1619
+ return basePrice > finalPrice && basePrice > 0;
1620
+ }
1621
+ function getDiscountPercentage(product) {
1622
+ const basePrice = getBasePrice(product);
1623
+ const finalPrice = getDisplayPrice(product);
1624
+ if (basePrice > finalPrice && basePrice > 0) {
1625
+ return Math.round((basePrice - finalPrice) / basePrice * 100);
1626
+ }
1627
+ return 0;
1628
+ }
1629
+ function getMarkupPercentage(product) {
1630
+ const basePrice = getBasePrice(product);
1631
+ const finalPrice = getDisplayPrice(product);
1632
+ if (finalPrice > basePrice && basePrice > 0) {
1633
+ return Math.round((finalPrice - basePrice) / basePrice * 100);
1634
+ }
1635
+ return 0;
1636
+ }
1637
+ function getProductCurrency(product) {
1638
+ if (product.price_path) {
1639
+ const parsed = parsePricePath(product.price_path);
1640
+ return parsed.currency || "GHS";
1641
+ } else if (product.price_info?.currency) {
1642
+ return product.price_info.currency;
1643
+ }
1644
+ return "GHS";
1645
+ }
1646
+ function formatProductPrice(product, locale = "en-US") {
1647
+ const price = getDisplayPrice(product);
1648
+ const currency = getProductCurrency(product);
1649
+ return formatPrice(price, currency, locale);
1650
+ }
1651
+
1652
+ // src/utils/payment.ts
1322
1653
  function categorizePaymentError(error, errorCode) {
1323
1654
  let message = "An unexpected error occurred during payment processing. Please try again or contact support.";
1324
1655
  let recoverable = true;
@@ -1457,4 +1788,4 @@ function detectMobileMoneyProvider(phoneNumber) {
1457
1788
  return null;
1458
1789
  }
1459
1790
 
1460
- export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, createCimplifyClient, detectMobileMoneyProvider, formatMoney, normalizePaymentResponse, normalizeStatusResponse, query };
1791
+ export { AUTHORIZATION_TYPE, AUTH_MUTATION, AuthService, BusinessService, CHECKOUT_MODE, CHECKOUT_MUTATION, CHECKOUT_STEP, CURRENCY_SYMBOLS, CartOperations, CatalogueQueries, CheckoutService as CheckoutOperations, CheckoutService, CimplifyClient, CimplifyError, DEFAULT_COUNTRY, DEFAULT_CURRENCY, InventoryService, LINK_MUTATION, LINK_QUERY, LinkService, LiteService, MOBILE_MONEY_PROVIDER, MOBILE_MONEY_PROVIDERS, ORDER_MUTATION, ORDER_TYPE, OrderQueries, PAYMENT_METHOD, PAYMENT_MUTATION, PAYMENT_STATE, PICKUP_TIME_TYPE, QueryBuilder, SchedulingService, categorizePaymentError, createCimplifyClient, detectMobileMoneyProvider, extractPriceInfo, formatMoney, formatNumberCompact, formatPrice, formatPriceAdjustment, formatPriceCompact, formatProductPrice, getBasePrice, getCurrencySymbol, getDiscountPercentage, getDisplayPrice, getMarkupPercentage, getProductCurrency, isOnSale, normalizePaymentResponse, normalizeStatusResponse, parsePrice, parsePricePath, parsedPriceToPriceInfo, query };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cimplify/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Cimplify Commerce SDK for storefronts",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",