@payloadcms/plugin-ecommerce 3.84.0-canary.1 → 3.84.0-internal.d5d6e43

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 (44) hide show
  1. package/dist/collections/orders/createOrdersCollection.d.ts +6 -0
  2. package/dist/collections/orders/createOrdersCollection.d.ts.map +1 -1
  3. package/dist/collections/orders/createOrdersCollection.js +7 -1
  4. package/dist/collections/orders/createOrdersCollection.js.map +1 -1
  5. package/dist/collections/transactions/createTransactionsCollection.d.ts +6 -0
  6. package/dist/collections/transactions/createTransactionsCollection.d.ts.map +1 -1
  7. package/dist/collections/transactions/createTransactionsCollection.js +7 -1
  8. package/dist/collections/transactions/createTransactionsCollection.js.map +1 -1
  9. package/dist/endpoints/confirmOrder.d.ts +11 -1
  10. package/dist/endpoints/confirmOrder.d.ts.map +1 -1
  11. package/dist/endpoints/confirmOrder.js +74 -2
  12. package/dist/endpoints/confirmOrder.js.map +1 -1
  13. package/dist/endpoints/initiatePayment.d.ts +11 -1
  14. package/dist/endpoints/initiatePayment.d.ts.map +1 -1
  15. package/dist/endpoints/initiatePayment.js +74 -3
  16. package/dist/endpoints/initiatePayment.js.map +1 -1
  17. package/dist/exports/types.d.ts +1 -1
  18. package/dist/exports/types.d.ts.map +1 -1
  19. package/dist/exports/types.js.map +1 -1
  20. package/dist/fields/summaryField.d.ts +14 -0
  21. package/dist/fields/summaryField.d.ts.map +1 -0
  22. package/dist/fields/summaryField.js +83 -0
  23. package/dist/fields/summaryField.js.map +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +11 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/payments/adapters/stripe/index.d.ts +2 -1
  28. package/dist/payments/adapters/stripe/index.d.ts.map +1 -1
  29. package/dist/payments/adapters/stripe/index.js.map +1 -1
  30. package/dist/payments/adapters/stripe/initiatePayment.d.ts.map +1 -1
  31. package/dist/payments/adapters/stripe/initiatePayment.js +6 -3
  32. package/dist/payments/adapters/stripe/initiatePayment.js.map +1 -1
  33. package/dist/types/index.d.ts +200 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/index.js.map +1 -1
  36. package/dist/utilities/runPaymentHooks.d.ts +28 -0
  37. package/dist/utilities/runPaymentHooks.d.ts.map +1 -0
  38. package/dist/utilities/runPaymentHooks.js +68 -0
  39. package/dist/utilities/runPaymentHooks.js.map +1 -0
  40. package/dist/utilities/runPaymentHooks.spec.js +324 -0
  41. package/dist/utilities/runPaymentHooks.spec.js.map +1 -0
  42. package/dist/utilities/sanitizePluginConfig.spec.js +35 -0
  43. package/dist/utilities/sanitizePluginConfig.spec.js.map +1 -1
  44. package/package.json +7 -7
@@ -12,6 +12,12 @@ type Props = {
12
12
  */
13
13
  customersSlug?: string;
14
14
  enableVariants?: boolean;
15
+ /**
16
+ * Whether payment hooks are configured. When true, a `summary` group field is
17
+ * added to the collection to record the breakdown (subtotal, tax, shipping, etc.)
18
+ * produced by the payment hook pipeline.
19
+ */
20
+ hasHooks?: boolean;
15
21
  /**
16
22
  * Slug of the products collection, defaults to 'products'.
17
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"createOrdersCollection.d.ts","sourceRoot":"","sources":["../../../src/collections/orders/createOrdersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAO1E,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,sBAAsB,GAAG,SAAS,GAAG,iBAAiB,CAAC,CAAA;IAClF;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBAwLtD,CAAA"}
1
+ {"version":3,"file":"createOrdersCollection.d.ts","sourceRoot":"","sources":["../../../src/collections/orders/createOrdersCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAQ1E,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,sBAAsB,GAAG,SAAS,GAAG,iBAAiB,CAAC,CAAA;IAClF;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBA0LtD,CAAA"}
@@ -1,9 +1,10 @@
1
1
  import { amountField } from '../../fields/amountField.js';
2
2
  import { cartItemsField } from '../../fields/cartItemsField.js';
3
3
  import { currencyField } from '../../fields/currencyField.js';
4
+ import { summaryField } from '../../fields/summaryField.js';
4
5
  import { accessOR } from '../../utilities/accessComposition.js';
5
6
  export const createOrdersCollection = (props)=>{
6
- const { access, addressFields, currenciesConfig, customersSlug = 'users', enableVariants = false, productsSlug = 'products', transactionsSlug = 'transactions', variantsSlug = 'variants' } = props || {};
7
+ const { access, addressFields, currenciesConfig, customersSlug = 'users', enableVariants = false, hasHooks = false, productsSlug = 'products', transactionsSlug = 'transactions', variantsSlug = 'variants' } = props || {};
7
8
  const fields = [
8
9
  {
9
10
  type: 'tabs',
@@ -130,6 +131,11 @@ export const createOrdersCollection = (props)=>{
130
131
  })
131
132
  ]
132
133
  }
134
+ ] : [],
135
+ ...hasHooks && currenciesConfig ? [
136
+ summaryField({
137
+ currenciesConfig
138
+ })
133
139
  ] : []
134
140
  ];
135
141
  const baseConfig = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/collections/orders/createOrdersCollection.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig } from '../../types/index.js'\n\nimport { amountField } from '../../fields/amountField.js'\nimport { cartItemsField } from '../../fields/cartItemsField.js'\nimport { currencyField } from '../../fields/currencyField.js'\nimport { accessOR } from '../../utilities/accessComposition.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'adminOnlyFieldAccess' | 'isAdmin' | 'isDocumentOwner'>\n /**\n * Array of fields used for capturing the shipping address data.\n */\n addressFields?: Field[]\n currenciesConfig?: CurrenciesConfig\n /**\n * Slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n enableVariants?: boolean\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the transactions collection, defaults to 'transactions'.\n */\n transactionsSlug?: string\n /**\n * Slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\nexport const createOrdersCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n addressFields,\n currenciesConfig,\n customersSlug = 'users',\n enableVariants = false,\n productsSlug = 'products',\n transactionsSlug = 'transactions',\n variantsSlug = 'variants',\n } = props || {}\n\n const fields: Field[] = [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n cartItemsField({\n enableVariants,\n overrides: {\n name: 'items',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:item'),\n },\n },\n productsSlug,\n variantsSlug,\n }),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:orderDetails'),\n },\n {\n fields: [\n ...(addressFields\n ? [\n {\n name: 'shippingAddress',\n type: 'group',\n fields: addressFields,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:shippingAddress'),\n } as Field,\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:shipping'),\n },\n ],\n },\n {\n name: 'customer',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customer'),\n relationTo: customersSlug,\n },\n {\n name: 'customerEmail',\n type: 'email',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customerEmail'),\n },\n {\n name: 'transactions',\n type: 'relationship',\n access: {\n create: access.adminOnlyFieldAccess,\n read: access.adminOnlyFieldAccess,\n update: access.adminOnlyFieldAccess,\n },\n admin: {\n position: 'sidebar',\n },\n hasMany: true,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactions'),\n relationTo: transactionsSlug,\n },\n {\n name: 'status',\n type: 'select',\n admin: {\n position: 'sidebar',\n },\n defaultValue: 'processing',\n interfaceName: 'OrderStatus',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:status'),\n options: [\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:processing'),\n value: 'processing',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:completed'),\n value: 'completed',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:cancelled'),\n value: 'cancelled',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:refunded'),\n value: 'refunded',\n },\n ],\n },\n\n ...(currenciesConfig\n ? [\n {\n type: 'row',\n admin: {\n position: 'sidebar',\n },\n fields: [\n amountField({\n currenciesConfig,\n }),\n currencyField({\n currenciesConfig,\n }),\n ],\n } as Field,\n ]\n : []),\n ]\n\n const baseConfig: CollectionConfig = {\n slug: 'orders',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: accessOR(access.isAdmin, access.isDocumentOwner),\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:ordersCollectionDescription'),\n group: 'Ecommerce',\n useAsTitle: 'createdAt',\n },\n fields,\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:orders'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:order'),\n },\n timestamps: true,\n }\n\n return { ...baseConfig }\n}\n"],"names":["amountField","cartItemsField","currencyField","accessOR","createOrdersCollection","props","access","addressFields","currenciesConfig","customersSlug","enableVariants","productsSlug","transactionsSlug","variantsSlug","fields","type","tabs","overrides","name","label","t","labels","plural","singular","admin","position","relationTo","create","adminOnlyFieldAccess","read","update","hasMany","defaultValue","interfaceName","options","value","baseConfig","slug","isAdmin","delete","isDocumentOwner","description","group","useAsTitle","timestamps"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/collections/orders/createOrdersCollection.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig } from '../../types/index.js'\n\nimport { amountField } from '../../fields/amountField.js'\nimport { cartItemsField } from '../../fields/cartItemsField.js'\nimport { currencyField } from '../../fields/currencyField.js'\nimport { summaryField } from '../../fields/summaryField.js'\nimport { accessOR } from '../../utilities/accessComposition.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'adminOnlyFieldAccess' | 'isAdmin' | 'isDocumentOwner'>\n /**\n * Array of fields used for capturing the shipping address data.\n */\n addressFields?: Field[]\n currenciesConfig?: CurrenciesConfig\n /**\n * Slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n enableVariants?: boolean\n /**\n * Whether payment hooks are configured. When true, a `summary` group field is\n * added to the collection to record the breakdown (subtotal, tax, shipping, etc.)\n * produced by the payment hook pipeline.\n */\n hasHooks?: boolean\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the transactions collection, defaults to 'transactions'.\n */\n transactionsSlug?: string\n /**\n * Slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\nexport const createOrdersCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n addressFields,\n currenciesConfig,\n customersSlug = 'users',\n enableVariants = false,\n hasHooks = false,\n productsSlug = 'products',\n transactionsSlug = 'transactions',\n variantsSlug = 'variants',\n } = props || {}\n\n const fields: Field[] = [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n cartItemsField({\n enableVariants,\n overrides: {\n name: 'items',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:item'),\n },\n },\n productsSlug,\n variantsSlug,\n }),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:orderDetails'),\n },\n {\n fields: [\n ...(addressFields\n ? [\n {\n name: 'shippingAddress',\n type: 'group',\n fields: addressFields,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:shippingAddress'),\n } as Field,\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:shipping'),\n },\n ],\n },\n {\n name: 'customer',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customer'),\n relationTo: customersSlug,\n },\n {\n name: 'customerEmail',\n type: 'email',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customerEmail'),\n },\n {\n name: 'transactions',\n type: 'relationship',\n access: {\n create: access.adminOnlyFieldAccess,\n read: access.adminOnlyFieldAccess,\n update: access.adminOnlyFieldAccess,\n },\n admin: {\n position: 'sidebar',\n },\n hasMany: true,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactions'),\n relationTo: transactionsSlug,\n },\n {\n name: 'status',\n type: 'select',\n admin: {\n position: 'sidebar',\n },\n defaultValue: 'processing',\n interfaceName: 'OrderStatus',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:status'),\n options: [\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:processing'),\n value: 'processing',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:completed'),\n value: 'completed',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:cancelled'),\n value: 'cancelled',\n },\n {\n // @ts-expect-error - translations are not typed in plugins yet\n label: ({ t }) => t('plugin-ecommerce:refunded'),\n value: 'refunded',\n },\n ],\n },\n\n ...(currenciesConfig\n ? [\n {\n type: 'row',\n admin: {\n position: 'sidebar',\n },\n fields: [\n amountField({\n currenciesConfig,\n }),\n currencyField({\n currenciesConfig,\n }),\n ],\n } as Field,\n ]\n : []),\n ...(hasHooks && currenciesConfig ? [summaryField({ currenciesConfig })] : []),\n ]\n\n const baseConfig: CollectionConfig = {\n slug: 'orders',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: accessOR(access.isAdmin, access.isDocumentOwner),\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:ordersCollectionDescription'),\n group: 'Ecommerce',\n useAsTitle: 'createdAt',\n },\n fields,\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:orders'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:order'),\n },\n timestamps: true,\n }\n\n return { ...baseConfig }\n}\n"],"names":["amountField","cartItemsField","currencyField","summaryField","accessOR","createOrdersCollection","props","access","addressFields","currenciesConfig","customersSlug","enableVariants","hasHooks","productsSlug","transactionsSlug","variantsSlug","fields","type","tabs","overrides","name","label","t","labels","plural","singular","admin","position","relationTo","create","adminOnlyFieldAccess","read","update","hasMany","defaultValue","interfaceName","options","value","baseConfig","slug","isAdmin","delete","isDocumentOwner","description","group","useAsTitle","timestamps"],"mappings":"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"}
@@ -19,6 +19,12 @@ type Props = {
19
19
  * Enable variants in the transactions collection.
20
20
  */
21
21
  enableVariants?: boolean;
22
+ /**
23
+ * Whether payment hooks are configured. When true, a `summary` group field is
24
+ * added to the collection to record the breakdown (subtotal, tax, shipping, etc.)
25
+ * produced by the payment hook pipeline.
26
+ */
27
+ hasHooks?: boolean;
22
28
  /**
23
29
  * Slug of the orders collection, defaults to 'orders'.
24
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"createTransactionsCollection.d.ts","sourceRoot":"","sources":["../../../src/collections/transactions/createTransactionsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAO1F,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IACrC;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,cAAc,EAAE,CAAA;IACjC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBA+K5D,CAAA"}
1
+ {"version":3,"file":"createTransactionsCollection.d.ts","sourceRoot":"","sources":["../../../src/collections/transactions/createTransactionsCollection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAQ1F,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IACrC;;OAEG;IACH,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,cAAc,EAAE,CAAA;IACjC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBAiL5D,CAAA"}
@@ -2,8 +2,9 @@ import { amountField } from '../../fields/amountField.js';
2
2
  import { cartItemsField } from '../../fields/cartItemsField.js';
3
3
  import { currencyField } from '../../fields/currencyField.js';
4
4
  import { statusField } from '../../fields/statusField.js';
5
+ import { summaryField } from '../../fields/summaryField.js';
5
6
  export const createTransactionsCollection = (props)=>{
6
- const { access, addressFields, cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', enableVariants = false, ordersSlug = 'orders', paymentMethods, productsSlug = 'products', variantsSlug = 'variants' } = props || {};
7
+ const { access, addressFields, cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', enableVariants = false, hasHooks = false, ordersSlug = 'orders', paymentMethods, productsSlug = 'products', variantsSlug = 'variants' } = props || {};
7
8
  const fields = [
8
9
  {
9
10
  type: 'tabs',
@@ -119,6 +120,11 @@ export const createTransactionsCollection = (props)=>{
119
120
  })
120
121
  ]
121
122
  }
123
+ ] : [],
124
+ ...hasHooks && currenciesConfig ? [
125
+ summaryField({
126
+ currenciesConfig
127
+ })
122
128
  ] : []
123
129
  ];
124
130
  const baseConfig = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/collections/transactions/createTransactionsCollection.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig, PaymentAdapter } from '../../types/index.js'\n\nimport { amountField } from '../../fields/amountField.js'\nimport { cartItemsField } from '../../fields/cartItemsField.js'\nimport { currencyField } from '../../fields/currencyField.js'\nimport { statusField } from '../../fields/statusField.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'isAdmin'>\n /**\n * Array of fields used for capturing the billing address.\n */\n addressFields?: Field[]\n /**\n * Slug of the carts collection, defaults to 'carts'.\n */\n cartsSlug?: string\n currenciesConfig?: CurrenciesConfig\n /**\n * Slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n /**\n * Enable variants in the transactions collection.\n */\n enableVariants?: boolean\n /**\n * Slug of the orders collection, defaults to 'orders'.\n */\n ordersSlug?: string\n paymentMethods?: PaymentAdapter[]\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\nexport const createTransactionsCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n addressFields,\n cartsSlug = 'carts',\n currenciesConfig,\n customersSlug = 'users',\n enableVariants = false,\n ordersSlug = 'orders',\n paymentMethods,\n productsSlug = 'products',\n variantsSlug = 'variants',\n } = props || {}\n\n const fields: Field[] = [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n cartItemsField({\n enableVariants,\n overrides: {\n name: 'items',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:item'),\n },\n },\n productsSlug,\n variantsSlug,\n }),\n ...(paymentMethods?.length && paymentMethods.length > 0\n ? [\n {\n name: 'paymentMethod',\n type: 'select',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:paymentMethod'),\n options: paymentMethods.map((method) => ({\n label: method.label ?? method.name,\n value: method.name,\n })),\n } as Field,\n ...(paymentMethods.map((method) => method.group) || []),\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactionDetails'),\n },\n {\n fields: [\n ...(addressFields\n ? [\n {\n name: 'billingAddress',\n type: 'group',\n fields: addressFields,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:billingAddress'),\n } as Field,\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:billing'),\n },\n ],\n },\n statusField({\n overrides: {\n admin: {\n position: 'sidebar',\n },\n },\n }),\n {\n name: 'customer',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customer'),\n relationTo: customersSlug,\n },\n {\n name: 'customerEmail',\n type: 'email',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customerEmail'),\n },\n {\n name: 'order',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:order'),\n relationTo: ordersSlug,\n },\n {\n name: 'cart',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n relationTo: cartsSlug,\n },\n ...(currenciesConfig\n ? [\n {\n type: 'row',\n admin: {\n position: 'sidebar',\n },\n fields: [\n amountField({\n currenciesConfig,\n }),\n currencyField({\n currenciesConfig,\n }),\n ],\n } as Field,\n ]\n : []),\n ]\n\n const baseConfig: CollectionConfig = {\n slug: 'transactions',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: access.isAdmin,\n update: access.isAdmin,\n },\n admin: {\n defaultColumns: ['createdAt', 'customer', 'order', 'amount', 'status'],\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactionsCollectionDescription'),\n group: 'Ecommerce',\n },\n fields,\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactions'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transaction'),\n },\n }\n\n return { ...baseConfig }\n}\n"],"names":["amountField","cartItemsField","currencyField","statusField","createTransactionsCollection","props","access","addressFields","cartsSlug","currenciesConfig","customersSlug","enableVariants","ordersSlug","paymentMethods","productsSlug","variantsSlug","fields","type","tabs","overrides","name","label","t","labels","plural","singular","length","options","map","method","value","group","admin","position","relationTo","baseConfig","slug","create","isAdmin","delete","read","update","defaultColumns","description"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/collections/transactions/createTransactionsCollection.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\n\nimport type { AccessConfig, CurrenciesConfig, PaymentAdapter } from '../../types/index.js'\n\nimport { amountField } from '../../fields/amountField.js'\nimport { cartItemsField } from '../../fields/cartItemsField.js'\nimport { currencyField } from '../../fields/currencyField.js'\nimport { statusField } from '../../fields/statusField.js'\nimport { summaryField } from '../../fields/summaryField.js'\n\ntype Props = {\n access: Pick<AccessConfig, 'isAdmin'>\n /**\n * Array of fields used for capturing the billing address.\n */\n addressFields?: Field[]\n /**\n * Slug of the carts collection, defaults to 'carts'.\n */\n cartsSlug?: string\n currenciesConfig?: CurrenciesConfig\n /**\n * Slug of the customers collection, defaults to 'users'.\n */\n customersSlug?: string\n /**\n * Enable variants in the transactions collection.\n */\n enableVariants?: boolean\n /**\n * Whether payment hooks are configured. When true, a `summary` group field is\n * added to the collection to record the breakdown (subtotal, tax, shipping, etc.)\n * produced by the payment hook pipeline.\n */\n hasHooks?: boolean\n /**\n * Slug of the orders collection, defaults to 'orders'.\n */\n ordersSlug?: string\n paymentMethods?: PaymentAdapter[]\n /**\n * Slug of the products collection, defaults to 'products'.\n */\n productsSlug?: string\n /**\n * Slug of the variants collection, defaults to 'variants'.\n */\n variantsSlug?: string\n}\n\nexport const createTransactionsCollection: (props: Props) => CollectionConfig = (props) => {\n const {\n access,\n addressFields,\n cartsSlug = 'carts',\n currenciesConfig,\n customersSlug = 'users',\n enableVariants = false,\n hasHooks = false,\n ordersSlug = 'orders',\n paymentMethods,\n productsSlug = 'products',\n variantsSlug = 'variants',\n } = props || {}\n\n const fields: Field[] = [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n cartItemsField({\n enableVariants,\n overrides: {\n name: 'items',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:items'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:item'),\n },\n },\n productsSlug,\n variantsSlug,\n }),\n ...(paymentMethods?.length && paymentMethods.length > 0\n ? [\n {\n name: 'paymentMethod',\n type: 'select',\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:paymentMethod'),\n options: paymentMethods.map((method) => ({\n label: method.label ?? method.name,\n value: method.name,\n })),\n } as Field,\n ...(paymentMethods.map((method) => method.group) || []),\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactionDetails'),\n },\n {\n fields: [\n ...(addressFields\n ? [\n {\n name: 'billingAddress',\n type: 'group',\n fields: addressFields,\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:billingAddress'),\n } as Field,\n ]\n : []),\n ],\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:billing'),\n },\n ],\n },\n statusField({\n overrides: {\n admin: {\n position: 'sidebar',\n },\n },\n }),\n {\n name: 'customer',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customer'),\n relationTo: customersSlug,\n },\n {\n name: 'customerEmail',\n type: 'email',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:customerEmail'),\n },\n {\n name: 'order',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n label: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:order'),\n relationTo: ordersSlug,\n },\n {\n name: 'cart',\n type: 'relationship',\n admin: {\n position: 'sidebar',\n },\n relationTo: cartsSlug,\n },\n ...(currenciesConfig\n ? [\n {\n type: 'row',\n admin: {\n position: 'sidebar',\n },\n fields: [\n amountField({\n currenciesConfig,\n }),\n currencyField({\n currenciesConfig,\n }),\n ],\n } as Field,\n ]\n : []),\n ...(hasHooks && currenciesConfig ? [summaryField({ currenciesConfig })] : []),\n ]\n\n const baseConfig: CollectionConfig = {\n slug: 'transactions',\n access: {\n create: access.isAdmin,\n delete: access.isAdmin,\n read: access.isAdmin,\n update: access.isAdmin,\n },\n admin: {\n defaultColumns: ['createdAt', 'customer', 'order', 'amount', 'status'],\n description: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactionsCollectionDescription'),\n group: 'Ecommerce',\n },\n fields,\n labels: {\n plural: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transactions'),\n singular: ({ t }) =>\n // @ts-expect-error - translations are not typed in plugins yet\n t('plugin-ecommerce:transaction'),\n },\n }\n\n return { ...baseConfig }\n}\n"],"names":["amountField","cartItemsField","currencyField","statusField","summaryField","createTransactionsCollection","props","access","addressFields","cartsSlug","currenciesConfig","customersSlug","enableVariants","hasHooks","ordersSlug","paymentMethods","productsSlug","variantsSlug","fields","type","tabs","overrides","name","label","t","labels","plural","singular","length","options","map","method","value","group","admin","position","relationTo","baseConfig","slug","create","isAdmin","delete","read","update","defaultColumns","description"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type Endpoint } from 'payload';
2
- import type { CurrenciesConfig, PaymentAdapter, ProductsValidation } from '../types/index.js';
2
+ import type { CurrenciesConfig, PaymentAdapter, PaymentHooks, ProductsValidation } from '../types/index.js';
3
3
  type Args = {
4
4
  /**
5
5
  * The slug of the carts collection, defaults to 'carts'.
@@ -10,10 +10,20 @@ type Args = {
10
10
  * The slug of the customers collection, defaults to 'users'.
11
11
  */
12
12
  customersSlug?: string;
13
+ /**
14
+ * Whether the transactions/orders collections have the `summary` field.
15
+ * When true, the handler copies the summary from the transaction onto the
16
+ * created order and includes it in the response.
17
+ */
18
+ hasHooks?: boolean;
13
19
  /**
14
20
  * The slug of the orders collection, defaults to 'orders'.
15
21
  */
16
22
  ordersSlug?: string;
23
+ /**
24
+ * Plugin-level payment hooks that run for all payment methods.
25
+ */
26
+ paymentHooks?: PaymentHooks;
17
27
  paymentMethod: PaymentAdapter;
18
28
  /**
19
29
  * The slug of the products collection, defaults to 'products'.
@@ -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,EAAuD,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE5F,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,kBAAkB,EACnB,MAAM,mBAAmB,CAAA;AAO1B,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;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,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,mBAsQ/B,CAAA"}
@@ -1,8 +1,9 @@
1
1
  import { addDataAndFileToRequest } from 'payload';
2
+ import { runAfterConfirmOrderHooks, runBeforeConfirmOrderHooks } from '../utilities/runPaymentHooks.js';
2
3
  /**
3
4
  * 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
5
  * This is the first step in the payment process.
5
- */ export const confirmOrderHandler = ({ cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', ordersSlug = 'orders', paymentMethod, productsSlug = 'products', productsValidation, transactionsSlug = 'transactions', variantsSlug = 'variants' })=>async (req)=>{
6
+ */ export const confirmOrderHandler = ({ cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', hasHooks = false, ordersSlug = 'orders', paymentHooks, paymentMethod, productsSlug = 'products', productsValidation, transactionsSlug = 'transactions', variantsSlug = 'variants' })=>async (req)=>{
6
7
  await addDataAndFileToRequest(req);
7
8
  const data = req.data;
8
9
  const payload = req.payload;
@@ -83,6 +84,29 @@ import { addDataAndFileToRequest } from 'payload';
83
84
  status: 400
84
85
  });
85
86
  }
87
+ // Run beforeConfirmOrder hooks (plugin-level then adapter-level)
88
+ const pluginBeforeHooks = paymentHooks?.beforeConfirmOrder ?? [];
89
+ const adapterBeforeHooks = paymentMethod.hooks?.beforeConfirmOrder ?? [];
90
+ const allBeforeConfirmHooks = [
91
+ ...pluginBeforeHooks,
92
+ ...adapterBeforeHooks
93
+ ];
94
+ if (allBeforeConfirmHooks.length > 0) {
95
+ try {
96
+ await runBeforeConfirmOrderHooks(allBeforeConfirmHooks, {
97
+ customerEmail,
98
+ data: data,
99
+ req
100
+ });
101
+ } catch (error) {
102
+ payload.logger.error(error, 'Error in beforeConfirmOrder hook.');
103
+ return Response.json({
104
+ message: error instanceof Error ? error.message : 'Error in beforeConfirmOrder hook.'
105
+ }, {
106
+ status: 400
107
+ });
108
+ }
109
+ }
86
110
  try {
87
111
  const paymentResponse = await paymentMethod.confirmOrder({
88
112
  cartsSlug,
@@ -95,6 +119,7 @@ import { addDataAndFileToRequest } from 'payload';
95
119
  req,
96
120
  transactionsSlug
97
121
  });
122
+ let persistedSummary;
98
123
  if (paymentResponse.transactionID) {
99
124
  const transaction = await payload.findByID({
100
125
  id: paymentResponse.transactionID,
@@ -102,9 +127,15 @@ import { addDataAndFileToRequest } from 'payload';
102
127
  depth: 0,
103
128
  select: {
104
129
  id: true,
105
- items: true
130
+ items: true,
131
+ ...hasHooks ? {
132
+ summary: true
133
+ } : {}
106
134
  }
107
135
  });
136
+ if (hasHooks && transaction && 'summary' in transaction) {
137
+ persistedSummary = transaction.summary;
138
+ }
108
139
  if (transaction && Array.isArray(transaction.items) && transaction.items.length > 0) {
109
140
  for (const item of transaction.items){
110
141
  if (item.variant) {
@@ -133,9 +164,50 @@ import { addDataAndFileToRequest } from 'payload';
133
164
  }
134
165
  }
135
166
  }
167
+ // Copy the summary from the transaction onto the order so the breakdown
168
+ // is available on both records. Errors are logged, not thrown — the order
169
+ // has already been successfully created by the adapter.
170
+ if (hasHooks && paymentResponse.orderID && persistedSummary) {
171
+ try {
172
+ await payload.update({
173
+ id: paymentResponse.orderID,
174
+ collection: ordersSlug,
175
+ data: {
176
+ summary: persistedSummary
177
+ },
178
+ overrideAccess: true,
179
+ req
180
+ });
181
+ } catch (error) {
182
+ payload.logger.error(error, 'Failed to copy summary onto order.');
183
+ }
184
+ }
185
+ // Run afterConfirmOrder hooks (plugin-level then adapter-level)
186
+ // Errors are logged but do not fail the response
187
+ if (paymentResponse.orderID && paymentResponse.transactionID) {
188
+ const pluginAfterHooks = paymentHooks?.afterConfirmOrder ?? [];
189
+ const adapterAfterHooks = paymentMethod.hooks?.afterConfirmOrder ?? [];
190
+ const allAfterConfirmHooks = [
191
+ ...pluginAfterHooks,
192
+ ...adapterAfterHooks
193
+ ];
194
+ if (allAfterConfirmHooks.length > 0) {
195
+ await runAfterConfirmOrderHooks(allAfterConfirmHooks, {
196
+ orderID: paymentResponse.orderID,
197
+ req,
198
+ transactionID: paymentResponse.transactionID
199
+ }, payload.logger);
200
+ }
201
+ }
136
202
  if ('paymentResponse.transactionID' in paymentResponse && paymentResponse.transactionID) {
137
203
  delete paymentResponse.transactionID;
138
204
  }
205
+ if (hasHooks && persistedSummary) {
206
+ return Response.json({
207
+ ...paymentResponse,
208
+ summary: persistedSummary
209
+ });
210
+ }
139
211
  return Response.json(paymentResponse);
140
212
  } catch (error) {
141
213
  payload.logger.error(error, 'Error confirming order.');
@@ -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 { addDataAndFileToRequest, type DefaultDocumentIDType, type Endpoint } from 'payload'\n\nimport type {\n CurrenciesConfig,\n PaymentAdapter,\n PaymentHooks,\n ProductsValidation,\n} from '../types/index.js'\n\nimport {\n runAfterConfirmOrderHooks,\n runBeforeConfirmOrderHooks,\n} from '../utilities/runPaymentHooks.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 * Whether the transactions/orders collections have the `summary` field.\n * When true, the handler copies the summary from the transaction onto the\n * created order and includes it in the response.\n */\n hasHooks?: boolean\n /**\n * The slug of the orders collection, defaults to 'orders'.\n */\n ordersSlug?: string\n /**\n * Plugin-level payment hooks that run for all payment methods.\n */\n paymentHooks?: PaymentHooks\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 hasHooks = false,\n ordersSlug = 'orders',\n paymentHooks,\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 // Run beforeConfirmOrder hooks (plugin-level then adapter-level)\n const pluginBeforeHooks = paymentHooks?.beforeConfirmOrder ?? []\n const adapterBeforeHooks = paymentMethod.hooks?.beforeConfirmOrder ?? []\n const allBeforeConfirmHooks = [...pluginBeforeHooks, ...adapterBeforeHooks]\n\n if (allBeforeConfirmHooks.length > 0) {\n try {\n await runBeforeConfirmOrderHooks(allBeforeConfirmHooks, {\n customerEmail,\n data: data as Record<string, unknown>,\n req,\n })\n } catch (error) {\n payload.logger.error(error, 'Error in beforeConfirmOrder hook.')\n\n return Response.json(\n {\n message: error instanceof Error ? error.message : 'Error in beforeConfirmOrder hook.',\n },\n {\n status: 400,\n },\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 let persistedSummary: unknown\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 ...(hasHooks ? { summary: true } : {}),\n },\n })\n\n if (hasHooks && transaction && 'summary' in transaction) {\n persistedSummary = (transaction as { summary?: unknown }).summary\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 // Copy the summary from the transaction onto the order so the breakdown\n // is available on both records. Errors are logged, not thrown — the order\n // has already been successfully created by the adapter.\n if (hasHooks && paymentResponse.orderID && persistedSummary) {\n try {\n await payload.update({\n id: paymentResponse.orderID,\n collection: ordersSlug,\n data: { summary: persistedSummary },\n overrideAccess: true,\n req,\n })\n } catch (error) {\n payload.logger.error(error, 'Failed to copy summary onto order.')\n }\n }\n\n // Run afterConfirmOrder hooks (plugin-level then adapter-level)\n // Errors are logged but do not fail the response\n if (paymentResponse.orderID && paymentResponse.transactionID) {\n const pluginAfterHooks = paymentHooks?.afterConfirmOrder ?? []\n const adapterAfterHooks = paymentMethod.hooks?.afterConfirmOrder ?? []\n const allAfterConfirmHooks = [...pluginAfterHooks, ...adapterAfterHooks]\n\n if (allAfterConfirmHooks.length > 0) {\n await runAfterConfirmOrderHooks(\n allAfterConfirmHooks,\n {\n orderID: paymentResponse.orderID,\n req,\n transactionID: paymentResponse.transactionID,\n },\n payload.logger,\n )\n }\n }\n\n if ('paymentResponse.transactionID' in paymentResponse && paymentResponse.transactionID) {\n delete (paymentResponse as Partial<typeof paymentResponse>).transactionID\n }\n\n if (hasHooks && persistedSummary) {\n return Response.json({ ...paymentResponse, summary: persistedSummary })\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","runAfterConfirmOrderHooks","runBeforeConfirmOrderHooks","confirmOrderHandler","cartsSlug","currenciesConfig","customersSlug","hasHooks","ordersSlug","paymentHooks","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","pluginBeforeHooks","beforeConfirmOrder","adapterBeforeHooks","hooks","allBeforeConfirmHooks","error","logger","Error","paymentResponse","confirmOrder","persistedSummary","transactionID","transaction","summary","item","variant","db","updateOne","inventory","$inc","quantity","product","orderID","update","pluginAfterHooks","afterConfirmOrder","adapterAfterHooks","allAfterConfirmHooks"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type Endpoint } from 'payload';
2
- import type { CurrenciesConfig, PaymentAdapter, ProductsValidation, SanitizedEcommercePluginConfig } from '../types/index.js';
2
+ import type { CurrenciesConfig, PaymentAdapter, PaymentHooks, ProductsValidation, SanitizedEcommercePluginConfig } from '../types/index.js';
3
3
  type Args = {
4
4
  /**
5
5
  * The slug of the carts collection, defaults to 'carts'.
@@ -10,11 +10,21 @@ type Args = {
10
10
  * The slug of the customers collection, defaults to 'users'.
11
11
  */
12
12
  customersSlug?: string;
13
+ /**
14
+ * Whether the transactions collection has the `summary` field. When true,
15
+ * the handler will persist the computed summary onto the transaction record
16
+ * after the adapter returns.
17
+ */
18
+ hasHooks?: boolean;
13
19
  /**
14
20
  * Track inventory stock for the products and variants.
15
21
  * Accepts an object to override the default field name.
16
22
  */
17
23
  inventory?: SanitizedEcommercePluginConfig['inventory'];
24
+ /**
25
+ * Plugin-level payment hooks that run for all payment methods.
26
+ */
27
+ paymentHooks?: PaymentHooks;
18
28
  paymentMethod: PaymentAdapter;
19
29
  /**
20
30
  * The slug of the products collection, defaults to 'products'.
@@ -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,YAAY,EACZ,kBAAkB,EAClB,8BAA8B,EAE/B,MAAM,mBAAmB,CAAA;AAK1B,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;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,8BAA8B,CAAC,WAAW,CAAC,CAAA;IACvD;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,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,eAwWlC,CAAA"}
@@ -1,9 +1,10 @@
1
1
  import { addDataAndFileToRequest } from 'payload';
2
2
  import { defaultProductsValidation } from '../utilities/defaultProductsValidation.js';
3
+ import { runBeforeInitiatePaymentHooks } from '../utilities/runPaymentHooks.js';
3
4
  /**
4
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.
5
6
  * This is the first step in the payment process.
6
- */ export const initiatePaymentHandler = ({ cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', paymentMethod, productsSlug = 'products', productsValidation, transactionsSlug = 'transactions', variantsSlug = 'variants' })=>async (req)=>{
7
+ */ export const initiatePaymentHandler = ({ cartsSlug = 'carts', currenciesConfig, customersSlug = 'users', hasHooks = false, paymentHooks, paymentMethod, productsSlug = 'products', productsValidation, transactionsSlug = 'transactions', variantsSlug = 'variants' })=>async (req)=>{
7
8
  await addDataAndFileToRequest(req);
8
9
  const data = req.data;
9
10
  const payload = req.payload;
@@ -199,6 +200,54 @@ import { defaultProductsValidation } from '../utilities/defaultProductsValidatio
199
200
  }
200
201
  }
201
202
  }
203
+ // Build the initial payment summary from the cart subtotal, then run hooks
204
+ // (plugin-level then adapter-level) to append tax, shipping, discounts, etc.
205
+ const cartSubtotal = cart.subtotal ?? 0;
206
+ let summary = {
207
+ currency,
208
+ lines: [
209
+ {
210
+ type: 'subtotal',
211
+ amount: cartSubtotal,
212
+ label: 'Subtotal'
213
+ }
214
+ ],
215
+ total: cartSubtotal
216
+ };
217
+ const pluginHooks = paymentHooks?.beforeInitiatePayment ?? [];
218
+ const adapterHooks = paymentMethod.hooks?.beforeInitiatePayment ?? [];
219
+ const allBeforeInitiateHooks = [
220
+ ...pluginHooks,
221
+ ...adapterHooks
222
+ ];
223
+ if (allBeforeInitiateHooks.length > 0) {
224
+ try {
225
+ summary = await runBeforeInitiatePaymentHooks(allBeforeInitiateHooks, {
226
+ billingAddress,
227
+ cart,
228
+ currenciesConfig,
229
+ currency,
230
+ customerEmail,
231
+ req,
232
+ shippingAddress,
233
+ summary
234
+ });
235
+ } catch (error) {
236
+ payload.logger.error(error, 'Error in beforeInitiatePayment hook.');
237
+ return Response.json({
238
+ message: error instanceof Error ? error.message : 'Error in beforeInitiatePayment hook.'
239
+ }, {
240
+ status: 400
241
+ });
242
+ }
243
+ }
244
+ if (summary.total <= 0) {
245
+ return Response.json({
246
+ message: 'Total after adjustments must be greater than zero.'
247
+ }, {
248
+ status: 400
249
+ });
250
+ }
202
251
  try {
203
252
  const paymentResponse = await paymentMethod.initiatePayment({
204
253
  customersSlug,
@@ -207,12 +256,34 @@ import { defaultProductsValidation } from '../utilities/defaultProductsValidatio
207
256
  cart,
208
257
  currency,
209
258
  customerEmail,
210
- shippingAddress
259
+ shippingAddress,
260
+ summary
211
261
  },
212
262
  req,
213
263
  transactionsSlug
214
264
  });
215
- return Response.json(paymentResponse);
265
+ // Persist the summary onto the transaction so the breakdown is queryable
266
+ // later (receipts, refunds, reporting). The adapter returns the transactionID
267
+ // when it has created a record; if not, persistence is skipped gracefully.
268
+ if (hasHooks && paymentResponse.transactionID) {
269
+ try {
270
+ await payload.update({
271
+ id: paymentResponse.transactionID,
272
+ collection: transactionsSlug,
273
+ data: {
274
+ summary
275
+ },
276
+ overrideAccess: true,
277
+ req
278
+ });
279
+ } catch (error) {
280
+ payload.logger.error(error, 'Failed to persist summary onto transaction.');
281
+ }
282
+ }
283
+ return Response.json({
284
+ ...paymentResponse,
285
+ summary
286
+ });
216
287
  } catch (error) {
217
288
  payload.logger.error(error, 'Error initiating payment.');
218
289
  return Response.json({