@payloadcms/plugin-ecommerce 4.0.0-internal.4804abd → 4.0.0-internal.4a6b4c3

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.
Files changed (154) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +6 -0
  3. package/dist/collections/addresses/createAddressesCollection.d.ts.map +1 -1
  4. package/dist/collections/addresses/createAddressesCollection.js +1 -0
  5. package/dist/collections/addresses/createAddressesCollection.js.map +1 -1
  6. package/dist/collections/addresses/hooks/beforeChange.d.ts.map +1 -1
  7. package/dist/collections/addresses/hooks/beforeChange.js +3 -2
  8. package/dist/collections/addresses/hooks/beforeChange.js.map +1 -1
  9. package/dist/collections/carts/beforeChange.d.ts.map +1 -1
  10. package/dist/collections/carts/beforeChange.js +2 -0
  11. package/dist/collections/carts/beforeChange.js.map +1 -1
  12. package/dist/collections/carts/createCartsCollection.d.ts.map +1 -1
  13. package/dist/collections/carts/createCartsCollection.js +1 -0
  14. package/dist/collections/carts/createCartsCollection.js.map +1 -1
  15. package/dist/collections/carts/endpoints/addItem.d.ts.map +1 -1
  16. package/dist/collections/carts/endpoints/clearCart.d.ts.map +1 -1
  17. package/dist/collections/carts/endpoints/mergeCart.d.ts.map +1 -1
  18. package/dist/collections/carts/endpoints/removeItem.d.ts.map +1 -1
  19. package/dist/collections/carts/endpoints/updateItem.d.ts.map +1 -1
  20. package/dist/collections/carts/hasCartSecretAccess.d.ts.map +1 -1
  21. package/dist/collections/carts/operations/addItem.d.ts.map +1 -1
  22. package/dist/collections/carts/operations/clearCart.d.ts.map +1 -1
  23. package/dist/collections/carts/operations/createRequestWithSecret.d.ts.map +1 -1
  24. package/dist/collections/carts/operations/mergeCart.d.ts.map +1 -1
  25. package/dist/collections/carts/operations/removeItem.d.ts.map +1 -1
  26. package/dist/collections/carts/operations/updateItem.d.ts.map +1 -1
  27. package/dist/collections/orders/createOrdersCollection.d.ts.map +1 -1
  28. package/dist/collections/orders/createOrdersCollection.js +1 -0
  29. package/dist/collections/orders/createOrdersCollection.js.map +1 -1
  30. package/dist/collections/products/createProductsCollection.d.ts.map +1 -1
  31. package/dist/collections/products/createProductsCollection.js +1 -0
  32. package/dist/collections/products/createProductsCollection.js.map +1 -1
  33. package/dist/collections/transactions/createTransactionsCollection.d.ts.map +1 -1
  34. package/dist/collections/transactions/createTransactionsCollection.js +1 -0
  35. package/dist/collections/transactions/createTransactionsCollection.js.map +1 -1
  36. package/dist/collections/variants/createVariantOptionsCollection.d.ts.map +1 -1
  37. package/dist/collections/variants/createVariantOptionsCollection.js +1 -0
  38. package/dist/collections/variants/createVariantOptionsCollection.js.map +1 -1
  39. package/dist/collections/variants/createVariantTypesCollection.d.ts.map +1 -1
  40. package/dist/collections/variants/createVariantTypesCollection.js +1 -0
  41. package/dist/collections/variants/createVariantTypesCollection.js.map +1 -1
  42. package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.d.ts.map +1 -1
  43. package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.js +2 -0
  44. package/dist/collections/variants/createVariantsCollection/hooks/beforeChange.js.map +1 -1
  45. package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.d.ts.map +1 -1
  46. package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.js +1 -0
  47. package/dist/collections/variants/createVariantsCollection/hooks/validateOptions.js.map +1 -1
  48. package/dist/collections/variants/createVariantsCollection/index.d.ts.map +1 -1
  49. package/dist/collections/variants/createVariantsCollection/index.js +1 -0
  50. package/dist/collections/variants/createVariantsCollection/index.js.map +1 -1
  51. package/dist/endpoints/confirmOrder.d.ts.map +1 -1
  52. package/dist/endpoints/confirmOrder.js +306 -44
  53. package/dist/endpoints/confirmOrder.js.map +1 -1
  54. package/dist/endpoints/initiatePayment.d.ts.map +1 -1
  55. package/dist/endpoints/initiatePayment.js +2 -0
  56. package/dist/endpoints/initiatePayment.js.map +1 -1
  57. package/dist/exports/types.d.ts +1 -1
  58. package/dist/exports/types.d.ts.map +1 -1
  59. package/dist/exports/types.js.map +1 -1
  60. package/dist/fields/pricesField.d.ts.map +1 -1
  61. package/dist/fields/pricesField.js +39 -39
  62. package/dist/fields/pricesField.js.map +1 -1
  63. package/dist/fields/statusField.d.ts.map +1 -1
  64. package/dist/fields/statusField.js +5 -0
  65. package/dist/fields/statusField.js.map +1 -1
  66. package/dist/index.d.ts +1 -2
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +7 -2
  69. package/dist/index.js.map +1 -1
  70. package/dist/payments/adapters/stripe/confirmOrder.d.ts.map +1 -1
  71. package/dist/payments/adapters/stripe/confirmOrder.js +108 -75
  72. package/dist/payments/adapters/stripe/confirmOrder.js.map +1 -1
  73. package/dist/payments/adapters/stripe/initiatePayment.d.ts.map +1 -1
  74. package/dist/payments/adapters/stripe/initiatePayment.js +1 -0
  75. package/dist/payments/adapters/stripe/initiatePayment.js.map +1 -1
  76. package/dist/payments/adapters/stripe/validateSettlement.d.ts +37 -0
  77. package/dist/payments/adapters/stripe/validateSettlement.d.ts.map +1 -0
  78. package/dist/payments/adapters/stripe/validateSettlement.js +157 -0
  79. package/dist/payments/adapters/stripe/validateSettlement.js.map +1 -0
  80. package/dist/react/provider/index.d.ts.map +1 -1
  81. package/dist/react/provider/index.js +75 -34
  82. package/dist/react/provider/index.js.map +1 -1
  83. package/dist/react/provider/utilities.d.ts.map +1 -1
  84. package/dist/translations/languages/ar.d.ts.map +1 -1
  85. package/dist/translations/languages/az.d.ts.map +1 -1
  86. package/dist/translations/languages/bg.d.ts.map +1 -1
  87. package/dist/translations/languages/ca.d.ts.map +1 -1
  88. package/dist/translations/languages/cs.d.ts.map +1 -1
  89. package/dist/translations/languages/da.d.ts.map +1 -1
  90. package/dist/translations/languages/de.d.ts.map +1 -1
  91. package/dist/translations/languages/en.d.ts.map +1 -1
  92. package/dist/translations/languages/es.d.ts.map +1 -1
  93. package/dist/translations/languages/et.d.ts.map +1 -1
  94. package/dist/translations/languages/fa.d.ts.map +1 -1
  95. package/dist/translations/languages/fr.d.ts.map +1 -1
  96. package/dist/translations/languages/he.d.ts.map +1 -1
  97. package/dist/translations/languages/hr.d.ts.map +1 -1
  98. package/dist/translations/languages/hu.d.ts.map +1 -1
  99. package/dist/translations/languages/hy.d.ts.map +1 -1
  100. package/dist/translations/languages/is.d.ts.map +1 -1
  101. package/dist/translations/languages/it.d.ts.map +1 -1
  102. package/dist/translations/languages/ja.d.ts.map +1 -1
  103. package/dist/translations/languages/ko.d.ts.map +1 -1
  104. package/dist/translations/languages/lt.d.ts.map +1 -1
  105. package/dist/translations/languages/my.d.ts.map +1 -1
  106. package/dist/translations/languages/nb.d.ts.map +1 -1
  107. package/dist/translations/languages/nl.d.ts.map +1 -1
  108. package/dist/translations/languages/pl.d.ts.map +1 -1
  109. package/dist/translations/languages/pt.d.ts.map +1 -1
  110. package/dist/translations/languages/ro.d.ts.map +1 -1
  111. package/dist/translations/languages/rs.d.ts.map +1 -1
  112. package/dist/translations/languages/rsLatin.d.ts.map +1 -1
  113. package/dist/translations/languages/ru.d.ts.map +1 -1
  114. package/dist/translations/languages/sk.d.ts.map +1 -1
  115. package/dist/translations/languages/sl.d.ts.map +1 -1
  116. package/dist/translations/languages/sv.d.ts.map +1 -1
  117. package/dist/translations/languages/ta.d.ts.map +1 -1
  118. package/dist/translations/languages/th.d.ts.map +1 -1
  119. package/dist/translations/languages/tr.d.ts.map +1 -1
  120. package/dist/translations/languages/uk.d.ts.map +1 -1
  121. package/dist/translations/languages/vi.d.ts.map +1 -1
  122. package/dist/translations/languages/zh.d.ts.map +1 -1
  123. package/dist/translations/languages/zhTw.d.ts.map +1 -1
  124. package/dist/types/index.d.ts +33 -7
  125. package/dist/types/index.d.ts.map +1 -1
  126. package/dist/types/index.js.map +1 -1
  127. package/dist/ui/PriceInput/FormattedInput.js +2 -2
  128. package/dist/ui/PriceInput/FormattedInput.js.map +1 -1
  129. package/dist/ui/PriceInput/index.css +19 -31
  130. package/dist/ui/PriceRowLabel/index.css +2 -2
  131. package/dist/ui/VariantOptionsSelector/index.css +8 -10
  132. package/dist/ui/VariantOptionsSelector/index.d.ts.map +1 -1
  133. package/dist/ui/VariantOptionsSelector/index.js +3 -1
  134. package/dist/ui/VariantOptionsSelector/index.js.map +1 -1
  135. package/dist/ui/utilities.d.ts.map +1 -1
  136. package/dist/utilities/accessComposition.d.ts.map +1 -1
  137. package/dist/utilities/getCollectionSlugMap.d.ts.map +1 -1
  138. package/dist/utilities/pushTypeScriptProperties.d.ts.map +1 -1
  139. package/dist/utilities/sanitizePluginConfig.d.ts.map +1 -1
  140. package/package.json +10 -10
  141. package/dist/@types/assets.d.js +0 -2
  142. package/dist/@types/assets.d.js.map +0 -1
  143. package/dist/collections/carts/operations/defaultCartItemMatcher.spec.js +0 -358
  144. package/dist/collections/carts/operations/defaultCartItemMatcher.spec.js.map +0 -1
  145. package/dist/payments/adapters/stripe/confirmOrder.spec.js +0 -166
  146. package/dist/payments/adapters/stripe/confirmOrder.spec.js.map +0 -1
  147. package/dist/utilities/accessComposition.spec.js +0 -765
  148. package/dist/utilities/accessComposition.spec.js.map +0 -1
  149. package/dist/utilities/defaultProductsValidation.spec.js +0 -384
  150. package/dist/utilities/defaultProductsValidation.spec.js.map +0 -1
  151. package/dist/utilities/getCollectionSlugMap.spec.js +0 -254
  152. package/dist/utilities/getCollectionSlugMap.spec.js.map +0 -1
  153. package/dist/utilities/sanitizePluginConfig.spec.js +0 -516
  154. package/dist/utilities/sanitizePluginConfig.spec.js.map +0 -1
@@ -6,6 +6,7 @@ export const variantsCollectionBeforeChange = ({ productsSlug, variantOptionsSlu
6
6
  id: productID,
7
7
  collection: productsSlug,
8
8
  depth: 0,
9
+ overrideAccess: true,
9
10
  select: {
10
11
  title: true,
11
12
  variantTypes: true
@@ -19,6 +20,7 @@ export const variantsCollectionBeforeChange = ({ productsSlug, variantOptionsSlu
19
20
  id: option,
20
21
  collection: variantOptionsSlug,
21
22
  depth: 0,
23
+ overrideAccess: true,
22
24
  select: {
23
25
  label: true
24
26
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook } from 'payload'\n\ntype Props = {\n productsSlug: string\n variantOptionsSlug: string\n}\n\nexport const variantsCollectionBeforeChange: (args: Props) => CollectionBeforeChangeHook =\n ({ productsSlug, variantOptionsSlug }) =>\n async ({ data, req }) => {\n if (data?.options?.length && data.options.length > 0) {\n const titleArray: string[] = []\n const productID = data.product\n const product = await req.payload.findByID({\n id: productID,\n collection: productsSlug,\n depth: 0,\n select: {\n title: true,\n variantTypes: true,\n },\n })\n\n if (product.title && typeof product.title === 'string') {\n titleArray.push(product.title)\n }\n\n for (const option of data.options) {\n const variantOption = await req.payload.findByID({\n id: option,\n collection: variantOptionsSlug,\n depth: 0,\n select: {\n label: true,\n },\n })\n\n if (!variantOption) {\n continue\n }\n\n if (variantOption.label && typeof variantOption.label === 'string') {\n titleArray.push(variantOption.label)\n }\n }\n\n data.title = titleArray.join(' — ')\n }\n\n return data\n }\n"],"names":["variantsCollectionBeforeChange","productsSlug","variantOptionsSlug","data","req","options","length","titleArray","productID","product","payload","findByID","id","collection","depth","select","title","variantTypes","push","option","variantOption","label","join"],"mappings":"AAOA,OAAO,MAAMA,iCACX,CAAC,EAAEC,YAAY,EAAEC,kBAAkB,EAAE,GACrC,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAE;QAClB,IAAID,MAAME,SAASC,UAAUH,KAAKE,OAAO,CAACC,MAAM,GAAG,GAAG;YACpD,MAAMC,aAAuB,EAAE;YAC/B,MAAMC,YAAYL,KAAKM,OAAO;YAC9B,MAAMA,UAAU,MAAML,IAAIM,OAAO,CAACC,QAAQ,CAAC;gBACzCC,IAAIJ;gBACJK,YAAYZ;gBACZa,OAAO;gBACPC,QAAQ;oBACNC,OAAO;oBACPC,cAAc;gBAChB;YACF;YAEA,IAAIR,QAAQO,KAAK,IAAI,OAAOP,QAAQO,KAAK,KAAK,UAAU;gBACtDT,WAAWW,IAAI,CAACT,QAAQO,KAAK;YAC/B;YAEA,KAAK,MAAMG,UAAUhB,KAAKE,OAAO,CAAE;gBACjC,MAAMe,gBAAgB,MAAMhB,IAAIM,OAAO,CAACC,QAAQ,CAAC;oBAC/CC,IAAIO;oBACJN,YAAYX;oBACZY,OAAO;oBACPC,QAAQ;wBACNM,OAAO;oBACT;gBACF;gBAEA,IAAI,CAACD,eAAe;oBAClB;gBACF;gBAEA,IAAIA,cAAcC,KAAK,IAAI,OAAOD,cAAcC,KAAK,KAAK,UAAU;oBAClEd,WAAWW,IAAI,CAACE,cAAcC,KAAK;gBACrC;YACF;YAEAlB,KAAKa,KAAK,GAAGT,WAAWe,IAAI,CAAC;QAC/B;QAEA,OAAOnB;IACT,EAAC"}
1
+ {"version":3,"sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/beforeChange.ts"],"sourcesContent":["import type { CollectionBeforeChangeHook } from 'payload'\n\ntype Props = {\n productsSlug: string\n variantOptionsSlug: string\n}\n\nexport const variantsCollectionBeforeChange: (args: Props) => CollectionBeforeChangeHook =\n ({ productsSlug, variantOptionsSlug }) =>\n async ({ data, req }) => {\n if (data?.options?.length && data.options.length > 0) {\n const titleArray: string[] = []\n const productID = data.product\n const product = await req.payload.findByID({\n id: productID,\n collection: productsSlug,\n depth: 0,\n overrideAccess: true,\n select: {\n title: true,\n variantTypes: true,\n },\n })\n\n if (product.title && typeof product.title === 'string') {\n titleArray.push(product.title)\n }\n\n for (const option of data.options) {\n const variantOption = await req.payload.findByID({\n id: option,\n collection: variantOptionsSlug,\n depth: 0,\n overrideAccess: true,\n select: {\n label: true,\n },\n })\n\n if (!variantOption) {\n continue\n }\n\n if (variantOption.label && typeof variantOption.label === 'string') {\n titleArray.push(variantOption.label)\n }\n }\n\n data.title = titleArray.join(' — ')\n }\n\n return data\n }\n"],"names":["variantsCollectionBeforeChange","productsSlug","variantOptionsSlug","data","req","options","length","titleArray","productID","product","payload","findByID","id","collection","depth","overrideAccess","select","title","variantTypes","push","option","variantOption","label","join"],"mappings":"AAOA,OAAO,MAAMA,iCACX,CAAC,EAAEC,YAAY,EAAEC,kBAAkB,EAAE,GACrC,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAE;QAClB,IAAID,MAAME,SAASC,UAAUH,KAAKE,OAAO,CAACC,MAAM,GAAG,GAAG;YACpD,MAAMC,aAAuB,EAAE;YAC/B,MAAMC,YAAYL,KAAKM,OAAO;YAC9B,MAAMA,UAAU,MAAML,IAAIM,OAAO,CAACC,QAAQ,CAAC;gBACzCC,IAAIJ;gBACJK,YAAYZ;gBACZa,OAAO;gBACPC,gBAAgB;gBAChBC,QAAQ;oBACNC,OAAO;oBACPC,cAAc;gBAChB;YACF;YAEA,IAAIT,QAAQQ,KAAK,IAAI,OAAOR,QAAQQ,KAAK,KAAK,UAAU;gBACtDV,WAAWY,IAAI,CAACV,QAAQQ,KAAK;YAC/B;YAEA,KAAK,MAAMG,UAAUjB,KAAKE,OAAO,CAAE;gBACjC,MAAMgB,gBAAgB,MAAMjB,IAAIM,OAAO,CAACC,QAAQ,CAAC;oBAC/CC,IAAIQ;oBACJP,YAAYX;oBACZY,OAAO;oBACPC,gBAAgB;oBAChBC,QAAQ;wBACNM,OAAO;oBACT;gBACF;gBAEA,IAAI,CAACD,eAAe;oBAClB;gBACF;gBAEA,IAAIA,cAAcC,KAAK,IAAI,OAAOD,cAAcC,KAAK,KAAK,UAAU;oBAClEf,WAAWY,IAAI,CAACE,cAAcC,KAAK;gBACrC;YACF;YAEAnB,KAAKc,KAAK,GAAGV,WAAWgB,IAAI,CAAC;QAC/B;QAEA,OAAOpB;IACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"validateOptions.d.ts","sourceRoot":"","sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/validateOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,KAAK,KAAK,GAAG;IACX,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,QAoE9C,CAAA"}
1
+ {"version":3,"file":"validateOptions.d.ts","sourceRoot":"","sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/validateOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,KAAK,KAAK,GAAG;IACX,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,QAqE9C,CAAA"}
@@ -28,6 +28,7 @@ export const validateOptions = (props)=>async (values, { data, req })=>{
28
28
  }
29
29
  }
30
30
  },
31
+ overrideAccess: true,
31
32
  select: {
32
33
  variants: true,
33
34
  variantTypes: true
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/validateOptions.ts"],"sourcesContent":["import type { Validate } from 'payload'\n\ntype Props = {\n productsCollectionSlug?: string\n}\n\nexport const validateOptions: (props?: Props) => Validate =\n (props) =>\n async (values, { data, req }) => {\n const { productsCollectionSlug = 'products' } = props || {}\n const { t } = req\n\n if (!values || values.length === 0) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsRequired')\n }\n\n const productID = data.product\n\n if (!productID) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:productRequired')\n }\n\n const product = await req.payload.findByID({\n id: productID,\n collection: productsCollectionSlug,\n depth: 1,\n joins: {\n variants: {\n where: {\n deletedAt: { exists: false },\n ...(data.id && {\n id: {\n not_equals: data.id, // exclude the current variant from the search\n },\n }),\n },\n },\n },\n select: {\n variants: true,\n variantTypes: true,\n },\n user: req.user,\n })\n\n // @ts-expect-error - TODO: Fix types\n const variants = product.variants?.docs ?? []\n\n // @ts-expect-error - TODO: Fix types\n if (values.length < product?.variantTypes?.length) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsRequiredAll')\n }\n\n if (variants.length > 0) {\n const existingOptions: (number | string)[][] = []\n\n variants.forEach((variant: any) => {\n existingOptions.push(variant.options)\n })\n\n const exists = existingOptions.some(\n (combo) => combo.length === values.length && combo.every((val) => values.includes(val)),\n )\n\n if (exists) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsAlreadyExists')\n }\n }\n\n return true\n }\n"],"names":["validateOptions","props","values","data","req","productsCollectionSlug","t","length","productID","product","payload","findByID","id","collection","depth","joins","variants","where","deletedAt","exists","not_equals","select","variantTypes","user","docs","existingOptions","forEach","variant","push","options","some","combo","every","val","includes"],"mappings":"AAMA,OAAO,MAAMA,kBACX,CAACC,QACD,OAAOC,QAAQ,EAAEC,IAAI,EAAEC,GAAG,EAAE;QAC1B,MAAM,EAAEC,yBAAyB,UAAU,EAAE,GAAGJ,SAAS,CAAC;QAC1D,MAAM,EAAEK,CAAC,EAAE,GAAGF;QAEd,IAAI,CAACF,UAAUA,OAAOK,MAAM,KAAK,GAAG;YAClC,qCAAqC;YACrC,OAAOD,EAAE;QACX;QAEA,MAAME,YAAYL,KAAKM,OAAO;QAE9B,IAAI,CAACD,WAAW;YACd,qCAAqC;YACrC,OAAOF,EAAE;QACX;QAEA,MAAMG,UAAU,MAAML,IAAIM,OAAO,CAACC,QAAQ,CAAC;YACzCC,IAAIJ;YACJK,YAAYR;YACZS,OAAO;YACPC,OAAO;gBACLC,UAAU;oBACRC,OAAO;wBACLC,WAAW;4BAAEC,QAAQ;wBAAM;wBAC3B,GAAIhB,KAAKS,EAAE,IAAI;4BACbA,IAAI;gCACFQ,YAAYjB,KAAKS,EAAE;4BACrB;wBACF,CAAC;oBACH;gBACF;YACF;YACAS,QAAQ;gBACNL,UAAU;gBACVM,cAAc;YAChB;YACAC,MAAMnB,IAAImB,IAAI;QAChB;QAEA,qCAAqC;QACrC,MAAMP,WAAWP,QAAQO,QAAQ,EAAEQ,QAAQ,EAAE;QAE7C,qCAAqC;QACrC,IAAItB,OAAOK,MAAM,GAAGE,SAASa,cAAcf,QAAQ;YACjD,qCAAqC;YACrC,OAAOD,EAAE;QACX;QAEA,IAAIU,SAAST,MAAM,GAAG,GAAG;YACvB,MAAMkB,kBAAyC,EAAE;YAEjDT,SAASU,OAAO,CAAC,CAACC;gBAChBF,gBAAgBG,IAAI,CAACD,QAAQE,OAAO;YACtC;YAEA,MAAMV,SAASM,gBAAgBK,IAAI,CACjC,CAACC,QAAUA,MAAMxB,MAAM,KAAKL,OAAOK,MAAM,IAAIwB,MAAMC,KAAK,CAAC,CAACC,MAAQ/B,OAAOgC,QAAQ,CAACD;YAGpF,IAAId,QAAQ;gBACV,qCAAqC;gBACrC,OAAOb,EAAE;YACX;QACF;QAEA,OAAO;IACT,EAAC"}
1
+ {"version":3,"sources":["../../../../../src/collections/variants/createVariantsCollection/hooks/validateOptions.ts"],"sourcesContent":["import type { Validate } from 'payload'\n\ntype Props = {\n productsCollectionSlug?: string\n}\n\nexport const validateOptions: (props?: Props) => Validate =\n (props) =>\n async (values, { data, req }) => {\n const { productsCollectionSlug = 'products' } = props || {}\n const { t } = req\n\n if (!values || values.length === 0) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsRequired')\n }\n\n const productID = data.product\n\n if (!productID) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:productRequired')\n }\n\n const product = await req.payload.findByID({\n id: productID,\n collection: productsCollectionSlug,\n depth: 1,\n joins: {\n variants: {\n where: {\n deletedAt: { exists: false },\n ...(data.id && {\n id: {\n not_equals: data.id, // exclude the current variant from the search\n },\n }),\n },\n },\n },\n overrideAccess: true,\n select: {\n variants: true,\n variantTypes: true,\n },\n user: req.user,\n })\n\n // @ts-expect-error - TODO: Fix types\n const variants = product.variants?.docs ?? []\n\n // @ts-expect-error - TODO: Fix types\n if (values.length < product?.variantTypes?.length) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsRequiredAll')\n }\n\n if (variants.length > 0) {\n const existingOptions: (number | string)[][] = []\n\n variants.forEach((variant: any) => {\n existingOptions.push(variant.options)\n })\n\n const exists = existingOptions.some(\n (combo) => combo.length === values.length && combo.every((val) => values.includes(val)),\n )\n\n if (exists) {\n // @ts-expect-error - TODO: Fix types\n return t('ecommerce:variantOptionsAlreadyExists')\n }\n }\n\n return true\n }\n"],"names":["validateOptions","props","values","data","req","productsCollectionSlug","t","length","productID","product","payload","findByID","id","collection","depth","joins","variants","where","deletedAt","exists","not_equals","overrideAccess","select","variantTypes","user","docs","existingOptions","forEach","variant","push","options","some","combo","every","val","includes"],"mappings":"AAMA,OAAO,MAAMA,kBACX,CAACC,QACD,OAAOC,QAAQ,EAAEC,IAAI,EAAEC,GAAG,EAAE;QAC1B,MAAM,EAAEC,yBAAyB,UAAU,EAAE,GAAGJ,SAAS,CAAC;QAC1D,MAAM,EAAEK,CAAC,EAAE,GAAGF;QAEd,IAAI,CAACF,UAAUA,OAAOK,MAAM,KAAK,GAAG;YAClC,qCAAqC;YACrC,OAAOD,EAAE;QACX;QAEA,MAAME,YAAYL,KAAKM,OAAO;QAE9B,IAAI,CAACD,WAAW;YACd,qCAAqC;YACrC,OAAOF,EAAE;QACX;QAEA,MAAMG,UAAU,MAAML,IAAIM,OAAO,CAACC,QAAQ,CAAC;YACzCC,IAAIJ;YACJK,YAAYR;YACZS,OAAO;YACPC,OAAO;gBACLC,UAAU;oBACRC,OAAO;wBACLC,WAAW;4BAAEC,QAAQ;wBAAM;wBAC3B,GAAIhB,KAAKS,EAAE,IAAI;4BACbA,IAAI;gCACFQ,YAAYjB,KAAKS,EAAE;4BACrB;wBACF,CAAC;oBACH;gBACF;YACF;YACAS,gBAAgB;YAChBC,QAAQ;gBACNN,UAAU;gBACVO,cAAc;YAChB;YACAC,MAAMpB,IAAIoB,IAAI;QAChB;QAEA,qCAAqC;QACrC,MAAMR,WAAWP,QAAQO,QAAQ,EAAES,QAAQ,EAAE;QAE7C,qCAAqC;QACrC,IAAIvB,OAAOK,MAAM,GAAGE,SAASc,cAAchB,QAAQ;YACjD,qCAAqC;YACrC,OAAOD,EAAE;QACX;QAEA,IAAIU,SAAST,MAAM,GAAG,GAAG;YACvB,MAAMmB,kBAAyC,EAAE;YAEjDV,SAASW,OAAO,CAAC,CAACC;gBAChBF,gBAAgBG,IAAI,CAACD,QAAQE,OAAO;YACtC;YAEA,MAAMX,SAASO,gBAAgBK,IAAI,CACjC,CAACC,QAAUA,MAAMzB,MAAM,KAAKL,OAAOK,MAAM,IAAIyB,MAAMC,KAAK,CAAC,CAACC,MAAQhC,OAAOiC,QAAQ,CAACD;YAGpF,IAAIf,QAAQ;gBACV,qCAAqC;gBACrC,OAAOb,EAAE;YACX;QACF;QAEA,OAAO;IACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/collections/variants/createVariantsCollection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAS,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAO9F,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAA;IAChE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,eAAe,CAAA;IACrC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBA0GxD,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/collections/variants/createVariantsCollection/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAS,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAO9F,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAA;IAChE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,eAAe,CAAA;IACrC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBA2GxD,CAAA"}
@@ -79,6 +79,7 @@ export const createVariantsCollection = (props)=>{
79
79
  group: false,
80
80
  useAsTitle: 'title'
81
81
  },
82
+ authorship: false,
82
83
  fields,
83
84
  hooks: {
84
85
  beforeChange: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/collections/variants/createVariantsCollection/index.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig, InventoryConfig } from '../../../types/index.js'\n\nimport { inventoryField } from '../../../fields/inventoryField.js'\nimport { pricesField } from '../../../fields/pricesField.js'\nimport { variantsCollectionBeforeChange as beforeChange } from './hooks/beforeChange.js'\nimport { validateOptions } from './hooks/validateOptions.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'adminOrPublishedStatus' | 'isAdmin'>\n currenciesConfig?: CurrenciesConfig\n /**\n * Enables inventory tracking for variants. Defaults to true.\n */\n inventory?: boolean | InventoryConfig\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the variant options collection, defaults to 'variantOptions'.\n */\n variantOptionsSlug?: string\n /**\n * Slug of the variant types collection, defaults to 'variantTypes'.\n */\n variantTypesSlug?: string\n}\n\nexport const createVariantsCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n currenciesConfig,\n inventory = true,\n productsSlug = 'products',\n variantOptionsSlug = 'variantOptions',\n variantTypesSlug = 'variantTypes',\n } = props || {}\n const { supportedCurrencies } = currenciesConfig || {}\n\n const fields: Field[] = [\n {\n name: 'title',\n type: 'text',\n admin: {\n description:\n 'Used for administrative purposes, not shown to customers. This is populated by default.',\n },\n },\n {\n name: 'product',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n readOnly: true,\n },\n relationTo: productsSlug,\n required: true,\n },\n {\n // This might need to be a custom component, to show a selector for each variant that is\n // enabled on the parent product\n // - separate select inputs, each showing only a specific variant (w/ options)\n // - it will save data to the DB as IDs in this relationship field\n // and needs a validate function as well which enforces that the options are fully specified, and accurate\n name: 'options',\n type: 'relationship',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-ecommerce/rsc#VariantOptionsSelector',\n },\n },\n },\n custom: {\n productsSlug,\n variantTypesSlug,\n },\n hasMany: true,\n label: 'Variant options',\n relationTo: variantOptionsSlug,\n required: true,\n validate: validateOptions({ productsCollectionSlug: productsSlug }),\n },\n ...(inventory ? [inventoryField()] : []),\n ]\n\n if (supportedCurrencies?.length && supportedCurrencies.length > 0) {\n const currencyOptions: string[] = []\n\n supportedCurrencies.forEach((currency) => {\n currencyOptions.push(currency.code)\n })\n\n if (currenciesConfig) {\n fields.push(...pricesField({ currenciesConfig }))\n }\n }\n\n const baseConfig: CollectionConfig = {\n slug: 'variants',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: access.adminOrPublishedStatus,\n update: access.isAdmin,\n },\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variantsCollectionDescription'),\n group: false,\n useAsTitle: 'title',\n },\n fields,\n hooks: {\n beforeChange: [beforeChange({ productsSlug, variantOptionsSlug })],\n },\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variants'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variant'),\n },\n trash: true,\n versions: {\n drafts: {\n autosave: true,\n },\n },\n }\n\n return baseConfig\n}\n"],"names":["inventoryField","pricesField","variantsCollectionBeforeChange","beforeChange","validateOptions","createVariantsCollection","props","access","currenciesConfig","inventory","productsSlug","variantOptionsSlug","variantTypesSlug","supportedCurrencies","fields","name","type","admin","description","position","readOnly","relationTo","required","components","Field","path","custom","hasMany","label","validate","productsCollectionSlug","length","currencyOptions","forEach","currency","push","code","baseConfig","slug","create","isAdmin","delete","read","adminOrPublishedStatus","update","t","group","useAsTitle","hooks","labels","plural","singular","trash","versions","drafts","autosave"],"mappings":"AAIA,SAASA,cAAc,QAAQ,oCAAmC;AAClE,SAASC,WAAW,QAAQ,iCAAgC;AAC5D,SAASC,kCAAkCC,YAAY,QAAQ,0BAAyB;AACxF,SAASC,eAAe,QAAQ,6BAA4B;AAuB5D,OAAO,MAAMC,2BAA+D,CAACC;IAC3E,MAAM,EACJC,MAAM,EACNC,gBAAgB,EAChBC,YAAY,IAAI,EAChBC,eAAe,UAAU,EACzBC,qBAAqB,gBAAgB,EACrCC,mBAAmB,cAAc,EAClC,GAAGN,SAAS,CAAC;IACd,MAAM,EAAEO,mBAAmB,EAAE,GAAGL,oBAAoB,CAAC;IAErD,MAAMM,SAAkB;QACtB;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aACE;YACJ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLE,UAAU;gBACVC,UAAU;YACZ;YACAC,YAAYX;YACZY,UAAU;QACZ;QACA;YACE,wFAAwF;YACxF,gCAAgC;YAChC,8EAA8E;YAC9E,kEAAkE;YAClE,0GAA0G;YAC1GP,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLM,YAAY;oBACVC,OAAO;wBACLC,MAAM;oBACR;gBACF;YACF;YACAC,QAAQ;gBACNhB;gBACAE;YACF;YACAe,SAAS;YACTC,OAAO;YACPP,YAAYV;YACZW,UAAU;YACVO,UAAUzB,gBAAgB;gBAAE0B,wBAAwBpB;YAAa;QACnE;WACID,YAAY;YAACT;SAAiB,GAAG,EAAE;KACxC;IAED,IAAIa,qBAAqBkB,UAAUlB,oBAAoBkB,MAAM,GAAG,GAAG;QACjE,MAAMC,kBAA4B,EAAE;QAEpCnB,oBAAoBoB,OAAO,CAAC,CAACC;YAC3BF,gBAAgBG,IAAI,CAACD,SAASE,IAAI;QACpC;QAEA,IAAI5B,kBAAkB;YACpBM,OAAOqB,IAAI,IAAIlC,YAAY;gBAAEO;YAAiB;QAChD;IACF;IAEA,MAAM6B,aAA+B;QACnCC,MAAM;QACN/B,QAAQ;YACNgC,QAAQhC,OAAOiC,OAAO;YACtBC,QAAQlC,OAAOiC,OAAO;YACtBE,MAAMnC,OAAOoC,sBAAsB;YACnCC,QAAQrC,OAAOiC,OAAO;QACxB;QACAvB,OAAO;YACLC,aAAa,CAAC,EAAE2B,CAAC,EAAE,GACjB,+DAA+D;gBAC/DA,EAAE;YACJC,OAAO;YACPC,YAAY;QACd;QACAjC;QACAkC,OAAO;YACL7C,cAAc;gBAACA,aAAa;oBAAEO;oBAAcC;gBAAmB;aAAG;QACpE;QACAsC,QAAQ;YACNC,QAAQ,CAAC,EAAEL,CAAC,EAAE,GACZ,+DAA+D;gBAC/DA,EAAE;YACJM,UAAU,CAAC,EAAEN,CAAC,EAAE,GACd,+DAA+D;gBAC/DA,EAAE;QACN;QACAO,OAAO;QACPC,UAAU;YACRC,QAAQ;gBACNC,UAAU;YACZ;QACF;IACF;IAEA,OAAOlB;AACT,EAAC"}
1
+ {"version":3,"sources":["../../../../src/collections/variants/createVariantsCollection/index.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig, InventoryConfig } from '../../../types/index.js'\n\nimport { inventoryField } from '../../../fields/inventoryField.js'\nimport { pricesField } from '../../../fields/pricesField.js'\nimport { variantsCollectionBeforeChange as beforeChange } from './hooks/beforeChange.js'\nimport { validateOptions } from './hooks/validateOptions.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'adminOrPublishedStatus' | 'isAdmin'>\n currenciesConfig?: CurrenciesConfig\n /**\n * Enables inventory tracking for variants. Defaults to true.\n */\n inventory?: boolean | InventoryConfig\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the variant options collection, defaults to 'variantOptions'.\n */\n variantOptionsSlug?: string\n /**\n * Slug of the variant types collection, defaults to 'variantTypes'.\n */\n variantTypesSlug?: string\n}\n\nexport const createVariantsCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n currenciesConfig,\n inventory = true,\n productsSlug = 'products',\n variantOptionsSlug = 'variantOptions',\n variantTypesSlug = 'variantTypes',\n } = props || {}\n const { supportedCurrencies } = currenciesConfig || {}\n\n const fields: Field[] = [\n {\n name: 'title',\n type: 'text',\n admin: {\n description:\n 'Used for administrative purposes, not shown to customers. This is populated by default.',\n },\n },\n {\n name: 'product',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n readOnly: true,\n },\n relationTo: productsSlug,\n required: true,\n },\n {\n // This might need to be a custom component, to show a selector for each variant that is\n // enabled on the parent product\n // - separate select inputs, each showing only a specific variant (w/ options)\n // - it will save data to the DB as IDs in this relationship field\n // and needs a validate function as well which enforces that the options are fully specified, and accurate\n name: 'options',\n type: 'relationship',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-ecommerce/rsc#VariantOptionsSelector',\n },\n },\n },\n custom: {\n productsSlug,\n variantTypesSlug,\n },\n hasMany: true,\n label: 'Variant options',\n relationTo: variantOptionsSlug,\n required: true,\n validate: validateOptions({ productsCollectionSlug: productsSlug }),\n },\n ...(inventory ? [inventoryField()] : []),\n ]\n\n if (supportedCurrencies?.length && supportedCurrencies.length > 0) {\n const currencyOptions: string[] = []\n\n supportedCurrencies.forEach((currency) => {\n currencyOptions.push(currency.code)\n })\n\n if (currenciesConfig) {\n fields.push(...pricesField({ currenciesConfig }))\n }\n }\n\n const baseConfig: CollectionConfig = {\n slug: 'variants',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: access.adminOrPublishedStatus,\n update: access.isAdmin,\n },\n admin: {\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variantsCollectionDescription'),\n group: false,\n useAsTitle: 'title',\n },\n authorship: false,\n fields,\n hooks: {\n beforeChange: [beforeChange({ productsSlug, variantOptionsSlug })],\n },\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variants'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:variant'),\n },\n trash: true,\n versions: {\n drafts: {\n autosave: true,\n },\n },\n }\n\n return baseConfig\n}\n"],"names":["inventoryField","pricesField","variantsCollectionBeforeChange","beforeChange","validateOptions","createVariantsCollection","props","access","currenciesConfig","inventory","productsSlug","variantOptionsSlug","variantTypesSlug","supportedCurrencies","fields","name","type","admin","description","position","readOnly","relationTo","required","components","Field","path","custom","hasMany","label","validate","productsCollectionSlug","length","currencyOptions","forEach","currency","push","code","baseConfig","slug","create","isAdmin","delete","read","adminOrPublishedStatus","update","t","group","useAsTitle","authorship","hooks","labels","plural","singular","trash","versions","drafts","autosave"],"mappings":"AAIA,SAASA,cAAc,QAAQ,oCAAmC;AAClE,SAASC,WAAW,QAAQ,iCAAgC;AAC5D,SAASC,kCAAkCC,YAAY,QAAQ,0BAAyB;AACxF,SAASC,eAAe,QAAQ,6BAA4B;AAuB5D,OAAO,MAAMC,2BAA+D,CAACC;IAC3E,MAAM,EACJC,MAAM,EACNC,gBAAgB,EAChBC,YAAY,IAAI,EAChBC,eAAe,UAAU,EACzBC,qBAAqB,gBAAgB,EACrCC,mBAAmB,cAAc,EAClC,GAAGN,SAAS,CAAC;IACd,MAAM,EAAEO,mBAAmB,EAAE,GAAGL,oBAAoB,CAAC;IAErD,MAAMM,SAAkB;QACtB;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aACE;YACJ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLE,UAAU;gBACVC,UAAU;YACZ;YACAC,YAAYX;YACZY,UAAU;QACZ;QACA;YACE,wFAAwF;YACxF,gCAAgC;YAChC,8EAA8E;YAC9E,kEAAkE;YAClE,0GAA0G;YAC1GP,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLM,YAAY;oBACVC,OAAO;wBACLC,MAAM;oBACR;gBACF;YACF;YACAC,QAAQ;gBACNhB;gBACAE;YACF;YACAe,SAAS;YACTC,OAAO;YACPP,YAAYV;YACZW,UAAU;YACVO,UAAUzB,gBAAgB;gBAAE0B,wBAAwBpB;YAAa;QACnE;WACID,YAAY;YAACT;SAAiB,GAAG,EAAE;KACxC;IAED,IAAIa,qBAAqBkB,UAAUlB,oBAAoBkB,MAAM,GAAG,GAAG;QACjE,MAAMC,kBAA4B,EAAE;QAEpCnB,oBAAoBoB,OAAO,CAAC,CAACC;YAC3BF,gBAAgBG,IAAI,CAACD,SAASE,IAAI;QACpC;QAEA,IAAI5B,kBAAkB;YACpBM,OAAOqB,IAAI,IAAIlC,YAAY;gBAAEO;YAAiB;QAChD;IACF;IAEA,MAAM6B,aAA+B;QACnCC,MAAM;QACN/B,QAAQ;YACNgC,QAAQhC,OAAOiC,OAAO;YACtBC,QAAQlC,OAAOiC,OAAO;YACtBE,MAAMnC,OAAOoC,sBAAsB;YACnCC,QAAQrC,OAAOiC,OAAO;QACxB;QACAvB,OAAO;YACLC,aAAa,CAAC,EAAE2B,CAAC,EAAE,GACjB,+DAA+D;gBAC/DA,EAAE;YACJC,OAAO;YACPC,YAAY;QACd;QACAC,YAAY;QACZlC;QACAmC,OAAO;YACL9C,cAAc;gBAACA,aAAa;oBAAEO;oBAAcC;gBAAmB;aAAG;QACpE;QACAuC,QAAQ;YACNC,QAAQ,CAAC,EAAEN,CAAC,EAAE,GACZ,+DAA+D;gBAC/DA,EAAE;YACJO,UAAU,CAAC,EAAEP,CAAC,EAAE,GACd,+DAA+D;gBAC/DA,EAAE;QACN;QACAQ,OAAO;QACPC,UAAU;YACRC,QAAQ;gBACNC,UAAU;YACZ;QACF;IACF;IAEA,OAAOnB;AACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"confirmOrder.d.ts","sourceRoot":"","sources":["../../src/endpoints/confirmOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAE7F,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,cAAc,CAAA;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,mBA0L/B,CAAA"}
1
+ {"version":3,"file":"confirmOrder.d.ts","sourceRoot":"","sources":["../../src/endpoints/confirmOrder.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAGd,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAEnB,MAAM,mBAAmB,CAAA;AAS1B,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,cAAc,CAAA;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,KAAK,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,mBAgQ/B,CAAA"}
@@ -1,4 +1,6 @@
1
- import { addDataAndFileToRequest } from 'payload';
1
+ import { addDataAndFileToRequest, commitTransaction, initTransaction, killTransaction } from 'payload';
2
+ const SETTLEMENT_POLL_INTERVAL_MS = 25;
3
+ const SETTLEMENT_WAIT_TIMEOUT_MS = 500;
2
4
  /**
3
5
  * Handles the endpoint for initiating payments. We will handle checking the amount and product and variant prices here before it is sent to the payment provider.
4
6
  * This is the first step in the payment process.
@@ -26,7 +28,7 @@ import { addDataAndFileToRequest } from 'payload';
26
28
  }
27
29
  } else {
28
30
  // Get the email from the data if user is not available
29
- if (data?.customerEmail && typeof data.customerEmail === 'string') {
31
+ if (typeof data?.customerEmail === 'string' && normalizeEmail(data.customerEmail).length > 0) {
30
32
  customerEmail = data.customerEmail;
31
33
  } else {
32
34
  return Response.json({
@@ -83,62 +85,105 @@ import { addDataAndFileToRequest } from 'payload';
83
85
  status: 400
84
86
  });
85
87
  }
88
+ let shouldCommit = false;
86
89
  try {
90
+ const canonicalCartID = cart.id;
91
+ if (canonicalCartID === null || canonicalCartID === undefined || typeof canonicalCartID === 'string' && canonicalCartID.trim() === '') {
92
+ throw new Error('Canonical cart ID is required.');
93
+ }
94
+ const cartCustomerEmail = 'customerEmail' in cart ? cart.customerEmail : undefined;
95
+ const normalizedCartCustomerEmail = normalizeEmail(cartCustomerEmail);
96
+ const normalizedSubmittedCustomerEmail = normalizeEmail(customerEmail);
97
+ const canonicalEmail = user ? normalizeEmail(user.email) : normalizedCartCustomerEmail || normalizedSubmittedCustomerEmail;
98
+ if (!user && normalizedCartCustomerEmail && normalizedSubmittedCustomerEmail !== normalizedCartCustomerEmail) {
99
+ throw new Error('Customer email does not match the cart.');
100
+ }
101
+ shouldCommit = await initTransaction(req);
102
+ const hadActiveTransaction = Boolean(await req.transactionID);
103
+ let didCallFinalizeOrder = false;
104
+ let didFinalizeOrder = false;
105
+ let didRecoverTransientConflict = false;
106
+ let finalizedTransactionID;
107
+ const finalizeOrder = async ({ orderData, transactionID })=>{
108
+ if (didCallFinalizeOrder) {
109
+ throw new Error('Order settlement was already finalized for this request.');
110
+ }
111
+ didCallFinalizeOrder = true;
112
+ finalizedTransactionID = transactionID;
113
+ let order;
114
+ try {
115
+ order = await finalizeTransactionOrder({
116
+ cartID: canonicalCartID,
117
+ cartsSlug,
118
+ orderData,
119
+ ordersSlug,
120
+ productsSlug,
121
+ req,
122
+ transactionID,
123
+ transactionsSlug,
124
+ variantsSlug
125
+ });
126
+ } catch (error) {
127
+ if (!shouldCommit || !isTransientTransactionConflict(error)) {
128
+ throw error;
129
+ }
130
+ // MongoDB reports a losing transactional claim as a transient write conflict rather
131
+ // than a null compare-and-set result. Leave the aborted snapshot before polling.
132
+ await killTransaction(req);
133
+ shouldCommit = false;
134
+ order = await waitForCanonicalOrder({
135
+ ordersSlug,
136
+ req,
137
+ transactionID,
138
+ transactionsSlug
139
+ });
140
+ didRecoverTransientConflict = true;
141
+ }
142
+ didFinalizeOrder = true;
143
+ return order;
144
+ };
87
145
  const paymentResponse = await paymentMethod.confirmOrder({
88
146
  cartsSlug,
89
147
  customersSlug,
90
148
  data: {
91
149
  ...data,
92
- customerEmail
150
+ cartID: canonicalCartID,
151
+ customerEmail: canonicalEmail
93
152
  },
153
+ finalizeOrder,
94
154
  ordersSlug,
95
155
  req,
96
156
  transactionsSlug
97
157
  });
98
- if (paymentResponse.transactionID) {
99
- const transaction = await payload.findByID({
100
- id: paymentResponse.transactionID,
101
- collection: transactionsSlug,
102
- depth: 0,
103
- select: {
104
- id: true,
105
- items: true
106
- }
107
- });
108
- if (transaction && Array.isArray(transaction.items) && transaction.items.length > 0) {
109
- for (const item of transaction.items){
110
- if (item.variant) {
111
- const id = typeof item.variant === 'object' ? item.variant.id : item.variant;
112
- await payload.db.updateOne({
113
- id,
114
- collection: variantsSlug,
115
- data: {
116
- inventory: {
117
- $inc: item.quantity * -1
118
- }
119
- }
120
- });
121
- } else if (item.product) {
122
- const id = typeof item.product === 'object' ? item.product.id : item.product;
123
- await payload.db.updateOne({
124
- id,
125
- collection: productsSlug,
126
- data: {
127
- inventory: {
128
- $inc: item.quantity * -1
129
- }
130
- }
131
- });
132
- }
133
- }
134
- }
158
+ const hasActiveTransaction = Boolean(await req.transactionID);
159
+ const transactionID = paymentResponse.transactionID;
160
+ if (!isValidDocumentID(transactionID)) {
161
+ throw new Error('Transaction ID is missing or invalid.');
162
+ }
163
+ if (!didCallFinalizeOrder) {
164
+ throw new Error('Payment adapter did not finalize the order.');
165
+ }
166
+ if (!didFinalizeOrder) {
167
+ throw new Error('Order settlement did not complete successfully.');
168
+ }
169
+ if (didFinalizeOrder && getRelationshipID(transactionID) !== getRelationshipID(finalizedTransactionID)) {
170
+ throw new Error('Confirmation response transaction does not match the settlement.');
135
171
  }
136
- if ('paymentResponse.transactionID' in paymentResponse && paymentResponse.transactionID) {
137
- delete paymentResponse.transactionID;
172
+ if (hadActiveTransaction && !hasActiveTransaction && !didRecoverTransientConflict) {
173
+ throw new Error('Order confirmation lost its active transaction.');
174
+ }
175
+ if (shouldCommit && hasActiveTransaction) {
176
+ await commitTransaction(req);
138
177
  }
139
178
  return Response.json(paymentResponse);
140
- } catch (error) {
141
- payload.logger.error(error, 'Error confirming order.');
179
+ } catch (err) {
180
+ if (shouldCommit) {
181
+ await killTransaction(req);
182
+ }
183
+ payload.logger.error({
184
+ err,
185
+ msg: 'Error confirming order.'
186
+ });
142
187
  return Response.json({
143
188
  message: 'Error confirming order.'
144
189
  }, {
@@ -146,5 +191,222 @@ import { addDataAndFileToRequest } from 'payload';
146
191
  });
147
192
  }
148
193
  };
194
+ const normalizeEmail = (email)=>typeof email === 'string' ? email.trim().toLowerCase() : '';
195
+ const isValidDocumentID = (id)=>typeof id === 'number' && Number.isFinite(id) || typeof id === 'string' && id.trim().length > 0;
196
+ const finalizeTransactionOrder = async ({ cartID, cartsSlug, orderData, ordersSlug, productsSlug, req, transactionID, transactionsSlug, variantsSlug })=>{
197
+ if (!isValidDocumentID(transactionID)) {
198
+ throw new Error('Transaction ID is missing or invalid.');
199
+ }
200
+ if (!isRecord(orderData)) {
201
+ throw new Error('Order data is missing or invalid.');
202
+ }
203
+ const claimedTransaction = await req.payload.db.updateOne({
204
+ collection: transactionsSlug,
205
+ data: {
206
+ status: 'processing'
207
+ },
208
+ options: {
209
+ atomic: true
210
+ },
211
+ req,
212
+ where: {
213
+ and: [
214
+ {
215
+ id: {
216
+ equals: transactionID
217
+ }
218
+ },
219
+ {
220
+ status: {
221
+ equals: 'pending'
222
+ }
223
+ },
224
+ {
225
+ order: {
226
+ exists: false
227
+ }
228
+ }
229
+ ]
230
+ }
231
+ });
232
+ if (!claimedTransaction) {
233
+ return waitForCanonicalOrder({
234
+ ordersSlug,
235
+ req,
236
+ transactionID,
237
+ transactionsSlug
238
+ });
239
+ }
240
+ if (getRelationshipID(claimedTransaction.id) !== getRelationshipID(transactionID)) {
241
+ throw new Error('Claimed transaction does not match the requested transaction.');
242
+ }
243
+ const transaction = await req.payload.findByID({
244
+ id: transactionID,
245
+ collection: transactionsSlug,
246
+ depth: 0,
247
+ overrideAccess: true,
248
+ req
249
+ });
250
+ if (!transaction || getRelationshipID(transaction.id) !== getRelationshipID(transactionID) || transaction.status !== 'processing') {
251
+ throw new Error('Claimed transaction could not be loaded for settlement.');
252
+ }
253
+ const referencedOrders = await req.payload.find({
254
+ collection: ordersSlug,
255
+ depth: 0,
256
+ limit: 1,
257
+ overrideAccess: true,
258
+ pagination: false,
259
+ req,
260
+ where: {
261
+ transactions: {
262
+ equals: transactionID
263
+ }
264
+ }
265
+ });
266
+ if (referencedOrders.totalDocs !== 0 || referencedOrders.docs.length !== 0) {
267
+ throw new Error('An order already references the claimed transaction.');
268
+ }
269
+ const order = await req.payload.create({
270
+ collection: ordersSlug,
271
+ data: {
272
+ ...orderData,
273
+ transactions: [
274
+ transactionID
275
+ ]
276
+ },
277
+ overrideAccess: true,
278
+ req
279
+ });
280
+ const orderID = requireDocumentID({
281
+ fieldName: 'order ID',
282
+ value: order.id
283
+ });
284
+ await req.payload.update({
285
+ id: cartID,
286
+ collection: cartsSlug,
287
+ data: {
288
+ purchasedAt: new Date().toISOString()
289
+ },
290
+ overrideAccess: true,
291
+ req
292
+ });
293
+ await decrementInventory({
294
+ items: transaction.items,
295
+ productsSlug,
296
+ req,
297
+ variantsSlug
298
+ });
299
+ await req.payload.update({
300
+ id: transactionID,
301
+ collection: transactionsSlug,
302
+ data: {
303
+ order: orderID,
304
+ status: 'succeeded'
305
+ },
306
+ overrideAccess: true,
307
+ req
308
+ });
309
+ return order;
310
+ };
311
+ const decrementInventory = async ({ items, productsSlug, req, variantsSlug })=>{
312
+ if (!Array.isArray(items) || items.length === 0) {
313
+ throw new Error('Inventory transaction items are missing or invalid.');
314
+ }
315
+ for (const item of items){
316
+ if (!isRecord(item) || typeof item.quantity !== 'number' || !Number.isFinite(item.quantity) || item.quantity <= 0) {
317
+ throw new Error('Inventory item quantity is missing or invalid.');
318
+ }
319
+ const hasVariant = item.variant !== null && item.variant !== undefined;
320
+ const id = hasVariant ? item.variant : item.product;
321
+ if (!isValidDocumentID(id)) {
322
+ throw new Error('Inventory item target is missing or invalid.');
323
+ }
324
+ const updatedInventory = await req.payload.db.updateOne({
325
+ id,
326
+ collection: hasVariant ? variantsSlug : productsSlug,
327
+ data: {
328
+ inventory: {
329
+ $inc: item.quantity * -1
330
+ }
331
+ },
332
+ req
333
+ });
334
+ if (!updatedInventory) {
335
+ throw new Error('Inventory item could not be updated.');
336
+ }
337
+ }
338
+ };
339
+ const waitForCanonicalOrder = async ({ ordersSlug, req, transactionID, transactionsSlug })=>{
340
+ const deadline = Date.now() + SETTLEMENT_WAIT_TIMEOUT_MS;
341
+ do {
342
+ const transaction = await req.payload.findByID({
343
+ id: transactionID,
344
+ collection: transactionsSlug,
345
+ depth: 0,
346
+ overrideAccess: true,
347
+ req
348
+ });
349
+ if (!transaction) {
350
+ throw new Error('Canonical transaction was not found.');
351
+ }
352
+ if (transaction.status === 'succeeded') {
353
+ return findExactlyLinkedOrder({
354
+ orderID: transaction.order,
355
+ ordersSlug,
356
+ req,
357
+ transactionID
358
+ });
359
+ }
360
+ if (transaction.status !== 'pending' && transaction.status !== 'processing') {
361
+ throw new Error('Transaction is not available for settlement.');
362
+ }
363
+ if (Date.now() >= deadline) {
364
+ break;
365
+ }
366
+ await new Promise((resolve)=>setTimeout(resolve, Math.min(SETTLEMENT_POLL_INTERVAL_MS, deadline - Date.now())));
367
+ }while (Date.now() <= deadline)
368
+ throw new Error('Transaction settlement did not complete in time.');
369
+ };
370
+ const findExactlyLinkedOrder = async ({ orderID, ordersSlug, req, transactionID })=>{
371
+ const canonicalOrderID = requireDocumentID({
372
+ fieldName: 'order ID',
373
+ value: orderID
374
+ });
375
+ const result = await req.payload.find({
376
+ collection: ordersSlug,
377
+ depth: 0,
378
+ limit: 2,
379
+ overrideAccess: true,
380
+ pagination: false,
381
+ req,
382
+ where: {
383
+ transactions: {
384
+ equals: transactionID
385
+ }
386
+ }
387
+ });
388
+ if (result.totalDocs !== 1 || result.docs.length !== 1 || getRelationshipID(result.docs[0]?.id) !== getRelationshipID(canonicalOrderID)) {
389
+ throw new Error('Transaction does not have exactly one canonical linked order.');
390
+ }
391
+ return result.docs[0];
392
+ };
393
+ const getRelationshipID = (value)=>{
394
+ const id = isRecord(value) ? value.id : value;
395
+ return isValidDocumentID(id) ? String(id) : undefined;
396
+ };
397
+ const requireDocumentID = ({ fieldName, value })=>{
398
+ const id = isRecord(value) ? value.id : value;
399
+ if (!isValidDocumentID(id)) {
400
+ throw new Error(`${fieldName} is missing or invalid.`);
401
+ }
402
+ return id;
403
+ };
404
+ const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
405
+ const isTransientTransactionConflict = (error)=>{
406
+ if (!isRecord(error)) {
407
+ return false;
408
+ }
409
+ return error.code === 112 || error.codeName === 'WriteConflict' || Array.isArray(error.errorLabels) && error.errorLabels.includes('TransientTransactionError');
410
+ };
149
411
 
150
412
  //# sourceMappingURL=confirmOrder.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/confirmOrder.ts"],"sourcesContent":["import { addDataAndFileToRequest, type DefaultDocumentIDType, type Endpoint } from 'payload'\n\nimport type { CurrenciesConfig, PaymentAdapter, ProductsValidation } from '../types/index.js'\n\ntype Args = {\n /**\n * The slug of the carts collection, defaults to 'carts'.\n */\n cartsSlug?: string\n currenciesConfig: CurrenciesConfig\n /**\n * The slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n /**\n * The slug of the orders collection, defaults to 'orders'.\n */\n ordersSlug?: string\n paymentMethod: PaymentAdapter\n /**\n * The slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Customise the validation used for checking products or variants before a transaction is created.\n */\n productsValidation?: ProductsValidation\n /**\n * The slug of the transactions collection, defaults to 'transactions'.\n */\n transactionsSlug?: string\n /**\n * The slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\ntype ConfirmOrderHandler = (args: Args) => Endpoint['handler']\n\n/**\n * Handles the endpoint for initiating payments. We will handle checking the amount and product and variant prices here before it is sent to the payment provider.\n * This is the first step in the payment process.\n */\nexport const confirmOrderHandler: ConfirmOrderHandler =\n ({\n cartsSlug = 'carts',\n currenciesConfig,\n customersSlug = 'users',\n ordersSlug = 'orders',\n paymentMethod,\n productsSlug = 'products',\n productsValidation,\n transactionsSlug = 'transactions',\n variantsSlug = 'variants',\n }) =>\n async (req) => {\n await addDataAndFileToRequest(req)\n\n const data = req.data\n const payload = req.payload\n const user = req.user\n\n let currency: string = currenciesConfig.defaultCurrency\n let cartID: DefaultDocumentIDType = data?.cartID\n let cart = undefined\n let customerEmail: string = user?.email ?? ''\n const cartSecret = data?.secret\n\n if (user) {\n if (user.cart?.docs && Array.isArray(user.cart.docs) && user.cart.docs.length > 0) {\n if (!cartID && user.cart.docs[0]) {\n // Use the user's cart instead\n if (typeof user.cart.docs[0] === 'object') {\n cartID = user.cart.docs[0].id\n cart = user.cart.docs[0]\n } else {\n cartID = user.cart.docs[0]\n }\n }\n }\n } else {\n // Get the email from the data if user is not available\n if (data?.customerEmail && typeof data.customerEmail === 'string') {\n customerEmail = data.customerEmail\n } else {\n return Response.json(\n {\n message: 'A customer email is required to make a purchase.',\n },\n {\n status: 400,\n },\n )\n }\n }\n\n if (!cart) {\n if (cartID) {\n // Add cart secret to query for guest cart access control\n if (cartSecret && typeof cartSecret === 'string') {\n req.query = req.query || {}\n req.query.secret = cartSecret\n }\n\n cart = await payload.findByID({\n id: cartID,\n collection: cartsSlug,\n depth: 2,\n overrideAccess: false,\n req,\n select: {\n id: true,\n currency: true,\n customerEmail: true,\n items: true,\n subtotal: true,\n },\n })\n\n if (!cart) {\n return Response.json(\n {\n message: `Cart with ID ${cartID} not found.`,\n },\n {\n status: 404,\n },\n )\n }\n } else {\n return Response.json(\n {\n message: 'Cart ID is required.',\n },\n {\n status: 400,\n },\n )\n }\n }\n\n if (cart.currency && typeof cart.currency === 'string') {\n currency = cart.currency\n }\n\n // Ensure the currency is provided or inferred in some way\n if (!currency) {\n return Response.json(\n {\n message: 'Currency is required.',\n },\n {\n status: 400,\n },\n )\n }\n\n try {\n const paymentResponse = await paymentMethod.confirmOrder({\n cartsSlug,\n customersSlug,\n data: {\n ...data,\n customerEmail,\n },\n ordersSlug,\n req,\n transactionsSlug,\n })\n\n if (paymentResponse.transactionID) {\n const transaction = await payload.findByID({\n id: paymentResponse.transactionID,\n collection: transactionsSlug,\n depth: 0,\n select: {\n id: true,\n items: true,\n },\n })\n\n if (transaction && Array.isArray(transaction.items) && transaction.items.length > 0) {\n for (const item of transaction.items) {\n if (item.variant) {\n const id = typeof item.variant === 'object' ? item.variant.id : item.variant\n\n await payload.db.updateOne({\n id,\n collection: variantsSlug,\n data: {\n inventory: {\n $inc: item.quantity * -1,\n },\n },\n })\n } else if (item.product) {\n const id = typeof item.product === 'object' ? item.product.id : item.product\n\n await payload.db.updateOne({\n id,\n collection: productsSlug,\n data: {\n inventory: {\n $inc: item.quantity * -1,\n },\n },\n })\n }\n }\n }\n }\n\n if ('paymentResponse.transactionID' in paymentResponse && paymentResponse.transactionID) {\n delete (paymentResponse as Partial<typeof paymentResponse>).transactionID\n }\n\n return Response.json(paymentResponse)\n } catch (error) {\n payload.logger.error(error, 'Error confirming order.')\n\n return Response.json(\n {\n message: 'Error confirming order.',\n },\n {\n status: 500,\n },\n )\n }\n }\n"],"names":["addDataAndFileToRequest","confirmOrderHandler","cartsSlug","currenciesConfig","customersSlug","ordersSlug","paymentMethod","productsSlug","productsValidation","transactionsSlug","variantsSlug","req","data","payload","user","currency","defaultCurrency","cartID","cart","undefined","customerEmail","email","cartSecret","secret","docs","Array","isArray","length","id","Response","json","message","status","query","findByID","collection","depth","overrideAccess","select","items","subtotal","paymentResponse","confirmOrder","transactionID","transaction","item","variant","db","updateOne","inventory","$inc","quantity","product","error","logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoints/confirmOrder.ts"],"sourcesContent":["import {\n addDataAndFileToRequest,\n commitTransaction,\n type DefaultDocumentIDType,\n type Endpoint,\n initTransaction,\n killTransaction,\n} from 'payload'\n\nimport type {\n CurrenciesConfig,\n PaymentAdapter,\n ProductsValidation,\n UserWithCart,\n} from '../types/index.js'\n\ntype ConfirmOrderArgs = Parameters<PaymentAdapter['confirmOrder']>[0]\ntype FinalizeOrder = ConfirmOrderArgs['finalizeOrder']\ntype RecordValue = Record<string, unknown>\n\nconst SETTLEMENT_POLL_INTERVAL_MS = 25\nconst SETTLEMENT_WAIT_TIMEOUT_MS = 500\n\ntype Args = {\n /**\n * The slug of the carts collection, defaults to 'carts'.\n */\n cartsSlug?: string\n currenciesConfig: CurrenciesConfig\n /**\n * The slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n /**\n * The slug of the orders collection, defaults to 'orders'.\n */\n ordersSlug?: string\n paymentMethod: PaymentAdapter\n /**\n * The slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Customise the validation used for checking products or variants before a transaction is created.\n */\n productsValidation?: ProductsValidation\n /**\n * The slug of the transactions collection, defaults to 'transactions'.\n */\n transactionsSlug?: string\n /**\n * The slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\ntype ConfirmOrderHandler = (args: Args) => Endpoint['handler']\n\n/**\n * Handles the endpoint for initiating payments. We will handle checking the amount and product and variant prices here before it is sent to the payment provider.\n * This is the first step in the payment process.\n */\nexport const confirmOrderHandler: ConfirmOrderHandler =\n ({\n cartsSlug = 'carts',\n currenciesConfig,\n customersSlug = 'users',\n ordersSlug = 'orders',\n paymentMethod,\n productsSlug = 'products',\n productsValidation,\n transactionsSlug = 'transactions',\n variantsSlug = 'variants',\n }) =>\n async (req) => {\n await addDataAndFileToRequest(req)\n\n const data = req.data\n const payload = req.payload\n const user = req.user as null | UserWithCart\n\n let currency: string = currenciesConfig.defaultCurrency\n let cartID: DefaultDocumentIDType = data?.cartID\n let cart = undefined\n let customerEmail: string = user?.email ?? ''\n const cartSecret = data?.secret\n\n if (user) {\n if (user.cart?.docs && Array.isArray(user.cart.docs) && user.cart.docs.length > 0) {\n if (!cartID && user.cart.docs[0]) {\n // Use the user's cart instead\n if (typeof user.cart.docs[0] === 'object') {\n cartID = user.cart.docs[0].id\n cart = user.cart.docs[0]\n } else {\n cartID = user.cart.docs[0]\n }\n }\n }\n } else {\n // Get the email from the data if user is not available\n if (\n typeof data?.customerEmail === 'string' &&\n normalizeEmail(data.customerEmail).length > 0\n ) {\n customerEmail = data.customerEmail\n } else {\n return Response.json(\n {\n message: 'A customer email is required to make a purchase.',\n },\n {\n status: 400,\n },\n )\n }\n }\n\n if (!cart) {\n if (cartID) {\n // Add cart secret to query for guest cart access control\n if (cartSecret && typeof cartSecret === 'string') {\n req.query = req.query || {}\n req.query.secret = cartSecret\n }\n\n cart = await payload.findByID({\n id: cartID,\n collection: cartsSlug,\n depth: 2,\n overrideAccess: false,\n req,\n select: {\n id: true,\n currency: true,\n customerEmail: true,\n items: true,\n subtotal: true,\n },\n })\n\n if (!cart) {\n return Response.json(\n {\n message: `Cart with ID ${cartID} not found.`,\n },\n {\n status: 404,\n },\n )\n }\n } else {\n return Response.json(\n {\n message: 'Cart ID is required.',\n },\n {\n status: 400,\n },\n )\n }\n }\n\n if (cart.currency && typeof cart.currency === 'string') {\n currency = cart.currency\n }\n\n // Ensure the currency is provided or inferred in some way\n if (!currency) {\n return Response.json(\n {\n message: 'Currency is required.',\n },\n {\n status: 400,\n },\n )\n }\n\n let shouldCommit = false\n\n try {\n const canonicalCartID = cart.id\n if (\n canonicalCartID === null ||\n canonicalCartID === undefined ||\n (typeof canonicalCartID === 'string' && canonicalCartID.trim() === '')\n ) {\n throw new Error('Canonical cart ID is required.')\n }\n\n const cartCustomerEmail = 'customerEmail' in cart ? cart.customerEmail : undefined\n const normalizedCartCustomerEmail = normalizeEmail(cartCustomerEmail)\n const normalizedSubmittedCustomerEmail = normalizeEmail(customerEmail)\n const canonicalEmail = user\n ? normalizeEmail(user.email)\n : normalizedCartCustomerEmail || normalizedSubmittedCustomerEmail\n\n if (\n !user &&\n normalizedCartCustomerEmail &&\n normalizedSubmittedCustomerEmail !== normalizedCartCustomerEmail\n ) {\n throw new Error('Customer email does not match the cart.')\n }\n\n shouldCommit = await initTransaction(req)\n const hadActiveTransaction = Boolean(await req.transactionID)\n let didCallFinalizeOrder = false\n let didFinalizeOrder = false\n let didRecoverTransientConflict = false\n let finalizedTransactionID: DefaultDocumentIDType | undefined\n\n const finalizeOrder: FinalizeOrder = async ({ orderData, transactionID }) => {\n if (didCallFinalizeOrder) {\n throw new Error('Order settlement was already finalized for this request.')\n }\n\n didCallFinalizeOrder = true\n finalizedTransactionID = transactionID\n\n let order: RecordValue\n\n try {\n order = await finalizeTransactionOrder({\n cartID: canonicalCartID,\n cartsSlug,\n orderData,\n ordersSlug,\n productsSlug,\n req,\n transactionID,\n transactionsSlug,\n variantsSlug,\n })\n } catch (error) {\n if (!shouldCommit || !isTransientTransactionConflict(error)) {\n throw error\n }\n\n // MongoDB reports a losing transactional claim as a transient write conflict rather\n // than a null compare-and-set result. Leave the aborted snapshot before polling.\n await killTransaction(req)\n shouldCommit = false\n order = await waitForCanonicalOrder({\n ordersSlug,\n req,\n transactionID,\n transactionsSlug,\n })\n didRecoverTransientConflict = true\n }\n\n didFinalizeOrder = true\n\n return order\n }\n\n const paymentResponse = await paymentMethod.confirmOrder({\n cartsSlug,\n customersSlug,\n data: {\n ...data,\n cartID: canonicalCartID,\n customerEmail: canonicalEmail,\n },\n finalizeOrder,\n ordersSlug,\n req,\n transactionsSlug,\n })\n const hasActiveTransaction = Boolean(await req.transactionID)\n const transactionID = paymentResponse.transactionID\n\n if (!isValidDocumentID(transactionID)) {\n throw new Error('Transaction ID is missing or invalid.')\n }\n\n if (!didCallFinalizeOrder) {\n throw new Error('Payment adapter did not finalize the order.')\n }\n\n if (!didFinalizeOrder) {\n throw new Error('Order settlement did not complete successfully.')\n }\n\n if (\n didFinalizeOrder &&\n getRelationshipID(transactionID) !== getRelationshipID(finalizedTransactionID)\n ) {\n throw new Error('Confirmation response transaction does not match the settlement.')\n }\n\n if (hadActiveTransaction && !hasActiveTransaction && !didRecoverTransientConflict) {\n throw new Error('Order confirmation lost its active transaction.')\n }\n\n if (shouldCommit && hasActiveTransaction) {\n await commitTransaction(req)\n }\n\n return Response.json(paymentResponse)\n } catch (err) {\n if (shouldCommit) {\n await killTransaction(req)\n }\n\n payload.logger.error({ err, msg: 'Error confirming order.' })\n\n return Response.json(\n {\n message: 'Error confirming order.',\n },\n {\n status: 500,\n },\n )\n }\n }\n\nconst normalizeEmail = (email: unknown): string =>\n typeof email === 'string' ? email.trim().toLowerCase() : ''\n\nconst isValidDocumentID = (id: unknown): id is DefaultDocumentIDType =>\n (typeof id === 'number' && Number.isFinite(id)) ||\n (typeof id === 'string' && id.trim().length > 0)\n\nconst finalizeTransactionOrder = async ({\n cartID,\n cartsSlug,\n orderData,\n ordersSlug,\n productsSlug,\n req,\n transactionID,\n transactionsSlug,\n variantsSlug,\n}: {\n cartID: DefaultDocumentIDType\n cartsSlug: string\n orderData: Record<string, unknown>\n ordersSlug: string\n productsSlug: string\n req: ConfirmOrderArgs['req']\n transactionID: DefaultDocumentIDType\n transactionsSlug: string\n variantsSlug: string\n}): Promise<RecordValue> => {\n if (!isValidDocumentID(transactionID)) {\n throw new Error('Transaction ID is missing or invalid.')\n }\n\n if (!isRecord(orderData)) {\n throw new Error('Order data is missing or invalid.')\n }\n\n const claimedTransaction = await req.payload.db.updateOne({\n collection: transactionsSlug,\n data: { status: 'processing' },\n options: { atomic: true },\n req,\n where: {\n and: [\n { id: { equals: transactionID } },\n { status: { equals: 'pending' } },\n { order: { exists: false } },\n ],\n },\n })\n\n if (!claimedTransaction) {\n return waitForCanonicalOrder({ ordersSlug, req, transactionID, transactionsSlug })\n }\n\n if (getRelationshipID(claimedTransaction.id) !== getRelationshipID(transactionID)) {\n throw new Error('Claimed transaction does not match the requested transaction.')\n }\n\n const transaction = await req.payload.findByID({\n id: transactionID,\n collection: transactionsSlug,\n depth: 0,\n overrideAccess: true,\n req,\n })\n\n if (\n !transaction ||\n getRelationshipID(transaction.id) !== getRelationshipID(transactionID) ||\n transaction.status !== 'processing'\n ) {\n throw new Error('Claimed transaction could not be loaded for settlement.')\n }\n\n const referencedOrders = await req.payload.find({\n collection: ordersSlug,\n depth: 0,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n req,\n where: { transactions: { equals: transactionID } },\n })\n\n if (referencedOrders.totalDocs !== 0 || referencedOrders.docs.length !== 0) {\n throw new Error('An order already references the claimed transaction.')\n }\n\n const order = (await req.payload.create({\n collection: ordersSlug,\n data: {\n ...orderData,\n transactions: [transactionID],\n },\n overrideAccess: true,\n req,\n })) as RecordValue\n const orderID = requireDocumentID({ fieldName: 'order ID', value: order.id })\n\n await req.payload.update({\n id: cartID,\n collection: cartsSlug,\n data: { purchasedAt: new Date().toISOString() },\n overrideAccess: true,\n req,\n })\n\n await decrementInventory({\n items: transaction.items,\n productsSlug,\n req,\n variantsSlug,\n })\n\n await req.payload.update({\n id: transactionID,\n collection: transactionsSlug,\n data: { order: orderID, status: 'succeeded' },\n overrideAccess: true,\n req,\n })\n\n return order\n}\n\nconst decrementInventory = async ({\n items,\n productsSlug,\n req,\n variantsSlug,\n}: {\n items: unknown\n productsSlug: string\n req: ConfirmOrderArgs['req']\n variantsSlug: string\n}): Promise<void> => {\n if (!Array.isArray(items) || items.length === 0) {\n throw new Error('Inventory transaction items are missing or invalid.')\n }\n\n for (const item of items) {\n if (\n !isRecord(item) ||\n typeof item.quantity !== 'number' ||\n !Number.isFinite(item.quantity) ||\n item.quantity <= 0\n ) {\n throw new Error('Inventory item quantity is missing or invalid.')\n }\n\n const hasVariant = item.variant !== null && item.variant !== undefined\n const id = hasVariant ? item.variant : item.product\n\n if (!isValidDocumentID(id)) {\n throw new Error('Inventory item target is missing or invalid.')\n }\n\n const updatedInventory = await req.payload.db.updateOne({\n id,\n collection: hasVariant ? variantsSlug : productsSlug,\n data: { inventory: { $inc: item.quantity * -1 } },\n req,\n })\n\n if (!updatedInventory) {\n throw new Error('Inventory item could not be updated.')\n }\n }\n}\n\nconst waitForCanonicalOrder = async ({\n ordersSlug,\n req,\n transactionID,\n transactionsSlug,\n}: {\n ordersSlug: string\n req: ConfirmOrderArgs['req']\n transactionID: DefaultDocumentIDType\n transactionsSlug: string\n}): Promise<RecordValue> => {\n const deadline = Date.now() + SETTLEMENT_WAIT_TIMEOUT_MS\n\n do {\n const transaction = await req.payload.findByID({\n id: transactionID,\n collection: transactionsSlug,\n depth: 0,\n overrideAccess: true,\n req,\n })\n\n if (!transaction) {\n throw new Error('Canonical transaction was not found.')\n }\n\n if (transaction.status === 'succeeded') {\n return findExactlyLinkedOrder({\n orderID: transaction.order,\n ordersSlug,\n req,\n transactionID,\n })\n }\n\n if (transaction.status !== 'pending' && transaction.status !== 'processing') {\n throw new Error('Transaction is not available for settlement.')\n }\n\n if (Date.now() >= deadline) {\n break\n }\n\n await new Promise<void>((resolve) =>\n setTimeout(resolve, Math.min(SETTLEMENT_POLL_INTERVAL_MS, deadline - Date.now())),\n )\n } while (Date.now() <= deadline)\n\n throw new Error('Transaction settlement did not complete in time.')\n}\n\nconst findExactlyLinkedOrder = async ({\n orderID,\n ordersSlug,\n req,\n transactionID,\n}: {\n orderID: unknown\n ordersSlug: string\n req: ConfirmOrderArgs['req']\n transactionID: DefaultDocumentIDType\n}): Promise<RecordValue> => {\n const canonicalOrderID = requireDocumentID({ fieldName: 'order ID', value: orderID })\n const result = await req.payload.find({\n collection: ordersSlug,\n depth: 0,\n limit: 2,\n overrideAccess: true,\n pagination: false,\n req,\n where: { transactions: { equals: transactionID } },\n })\n\n if (\n result.totalDocs !== 1 ||\n result.docs.length !== 1 ||\n getRelationshipID(result.docs[0]?.id) !== getRelationshipID(canonicalOrderID)\n ) {\n throw new Error('Transaction does not have exactly one canonical linked order.')\n }\n\n return result.docs[0] as RecordValue\n}\n\nconst getRelationshipID = (value: unknown): string | undefined => {\n const id = isRecord(value) ? value.id : value\n\n return isValidDocumentID(id) ? String(id) : undefined\n}\n\nconst requireDocumentID = ({\n fieldName,\n value,\n}: {\n fieldName: string\n value: unknown\n}): DefaultDocumentIDType => {\n const id = isRecord(value) ? value.id : value\n\n if (!isValidDocumentID(id)) {\n throw new Error(`${fieldName} is missing or invalid.`)\n }\n\n return id\n}\n\nconst isRecord = (value: unknown): value is RecordValue =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst isTransientTransactionConflict = (error: unknown): boolean => {\n if (!isRecord(error)) {\n return false\n }\n\n return (\n error.code === 112 ||\n error.codeName === 'WriteConflict' ||\n (Array.isArray(error.errorLabels) && error.errorLabels.includes('TransientTransactionError'))\n )\n}\n"],"names":["addDataAndFileToRequest","commitTransaction","initTransaction","killTransaction","SETTLEMENT_POLL_INTERVAL_MS","SETTLEMENT_WAIT_TIMEOUT_MS","confirmOrderHandler","cartsSlug","currenciesConfig","customersSlug","ordersSlug","paymentMethod","productsSlug","productsValidation","transactionsSlug","variantsSlug","req","data","payload","user","currency","defaultCurrency","cartID","cart","undefined","customerEmail","email","cartSecret","secret","docs","Array","isArray","length","id","normalizeEmail","Response","json","message","status","query","findByID","collection","depth","overrideAccess","select","items","subtotal","shouldCommit","canonicalCartID","trim","Error","cartCustomerEmail","normalizedCartCustomerEmail","normalizedSubmittedCustomerEmail","canonicalEmail","hadActiveTransaction","Boolean","transactionID","didCallFinalizeOrder","didFinalizeOrder","didRecoverTransientConflict","finalizedTransactionID","finalizeOrder","orderData","order","finalizeTransactionOrder","error","isTransientTransactionConflict","waitForCanonicalOrder","paymentResponse","confirmOrder","hasActiveTransaction","isValidDocumentID","getRelationshipID","err","logger","msg","toLowerCase","Number","isFinite","isRecord","claimedTransaction","db","updateOne","options","atomic","where","and","equals","exists","transaction","referencedOrders","find","limit","pagination","transactions","totalDocs","create","orderID","requireDocumentID","fieldName","value","update","purchasedAt","Date","toISOString","decrementInventory","item","quantity","hasVariant","variant","product","updatedInventory","inventory","$inc","deadline","now","findExactlyLinkedOrder","Promise","resolve","setTimeout","Math","min","canonicalOrderID","result","String","code","codeName","errorLabels","includes"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"initiatePayment.d.ts","sourceRoot":"","sources":["../../src/endpoints/initiatePayment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE5F,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,8BAA8B,EAC/B,MAAM,mBAAmB,CAAA;AAI1B,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,8BAA8B,CAAC,WAAW,CAAC,CAAA;IACvD,aAAa,EAAE,cAAc,CAAA;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE1D;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAiSlC,CAAA"}
1
+ {"version":3,"file":"initiatePayment.d.ts","sourceRoot":"","sources":["../../src/endpoints/initiatePayment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE5F,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,8BAA8B,EAE/B,MAAM,mBAAmB,CAAA;AAI1B,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,8BAA8B,CAAC,WAAW,CAAC,CAAA;IACvD,aAAa,EAAE,cAAc,CAAA;IAC7B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAA;AAE1D;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,eAmSlC,CAAA"}
@@ -113,6 +113,7 @@ import { defaultProductsValidation } from '../utilities/defaultProductsValidatio
113
113
  id,
114
114
  collection: productsSlug,
115
115
  depth: 0,
116
+ overrideAccess: true,
116
117
  select: {
117
118
  inventory: true,
118
119
  [priceField]: true
@@ -158,6 +159,7 @@ import { defaultProductsValidation } from '../utilities/defaultProductsValidatio
158
159
  id,
159
160
  collection: variantsSlug,
160
161
  depth: 0,
162
+ overrideAccess: true,
161
163
  select: {
162
164
  inventory: true,
163
165
  [priceField]: true