@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.
- package/dist/collections/orders/createOrdersCollection.d.ts +6 -0
- package/dist/collections/orders/createOrdersCollection.d.ts.map +1 -1
- package/dist/collections/orders/createOrdersCollection.js +7 -1
- package/dist/collections/orders/createOrdersCollection.js.map +1 -1
- package/dist/collections/transactions/createTransactionsCollection.d.ts +6 -0
- package/dist/collections/transactions/createTransactionsCollection.d.ts.map +1 -1
- package/dist/collections/transactions/createTransactionsCollection.js +7 -1
- package/dist/collections/transactions/createTransactionsCollection.js.map +1 -1
- package/dist/endpoints/confirmOrder.d.ts +11 -1
- package/dist/endpoints/confirmOrder.d.ts.map +1 -1
- package/dist/endpoints/confirmOrder.js +74 -2
- package/dist/endpoints/confirmOrder.js.map +1 -1
- package/dist/endpoints/initiatePayment.d.ts +11 -1
- package/dist/endpoints/initiatePayment.d.ts.map +1 -1
- package/dist/endpoints/initiatePayment.js +74 -3
- package/dist/endpoints/initiatePayment.js.map +1 -1
- package/dist/exports/types.d.ts +1 -1
- package/dist/exports/types.d.ts.map +1 -1
- package/dist/exports/types.js.map +1 -1
- package/dist/fields/summaryField.d.ts +14 -0
- package/dist/fields/summaryField.d.ts.map +1 -0
- package/dist/fields/summaryField.js +83 -0
- package/dist/fields/summaryField.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/payments/adapters/stripe/index.d.ts +2 -1
- package/dist/payments/adapters/stripe/index.d.ts.map +1 -1
- package/dist/payments/adapters/stripe/index.js.map +1 -1
- package/dist/payments/adapters/stripe/initiatePayment.d.ts.map +1 -1
- package/dist/payments/adapters/stripe/initiatePayment.js +6 -3
- package/dist/payments/adapters/stripe/initiatePayment.js.map +1 -1
- package/dist/types/index.d.ts +200 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/runPaymentHooks.d.ts +28 -0
- package/dist/utilities/runPaymentHooks.d.ts.map +1 -0
- package/dist/utilities/runPaymentHooks.js +68 -0
- package/dist/utilities/runPaymentHooks.js.map +1 -0
- package/dist/utilities/runPaymentHooks.spec.js +324 -0
- package/dist/utilities/runPaymentHooks.spec.js.map +1 -0
- package/dist/utilities/sanitizePluginConfig.spec.js +35 -0
- package/dist/utilities/sanitizePluginConfig.spec.js.map +1 -1
- 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;
|
|
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;
|
|
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":"AAIA,SAASA,WAAW,QAAQ,8BAA6B;AACzD,SAASC,cAAc,QAAQ,iCAAgC;AAC/D,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,WAAW,QAAQ,8BAA6B;AAoCzD,OAAO,MAAMC,+BAAmE,CAACC;IAC/E,MAAM,EACJC,MAAM,EACNC,aAAa,EACbC,YAAY,OAAO,EACnBC,gBAAgB,EAChBC,gBAAgB,OAAO,EACvBC,iBAAiB,KAAK,EACtBC,aAAa,QAAQ,EACrBC,cAAc,EACdC,eAAe,UAAU,EACzBC,eAAe,UAAU,EAC1B,GAAGV,SAAS,CAAC;IAEd,MAAMW,SAAkB;QACtB;YACEC,MAAM;YACNC,MAAM;gBACJ;oBACEF,QAAQ;wBACNf,eAAe;4BACbU;4BACAQ,WAAW;gCACTC,MAAM;gCACNC,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;oCAC/DA,EAAE;gCACJC,QAAQ;oCACNC,QAAQ,CAAC,EAAEF,CAAC,EAAE,GACZ,+DAA+D;wCAC/DA,EAAE;oCACJG,UAAU,CAAC,EAAEH,CAAC,EAAE,GACd,+DAA+D;wCAC/DA,EAAE;gCACN;4BACF;4BACAR;4BACAC;wBACF;2BACIF,gBAAgBa,UAAUb,eAAea,MAAM,GAAG,IAClD;4BACE;gCACEN,MAAM;gCACNH,MAAM;gCACNI,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;oCAC/DA,EAAE;gCACJK,SAASd,eAAee,GAAG,CAAC,CAACC,SAAY,CAAA;wCACvCR,OAAOQ,OAAOR,KAAK,IAAIQ,OAAOT,IAAI;wCAClCU,OAAOD,OAAOT,IAAI;oCACpB,CAAA;4BACF;+BACIP,eAAee,GAAG,CAAC,CAACC,SAAWA,OAAOE,KAAK,KAAK,EAAE;yBACvD,GACD,EAAE;qBACP;oBACDV,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;wBAC/DA,EAAE;gBACN;gBACA;oBACEN,QAAQ;2BACFT,gBACA;4BACE;gCACEa,MAAM;gCACNH,MAAM;gCACND,QAAQT;gCACRc,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;oCAC/DA,EAAE;4BACN;yBACD,GACD,EAAE;qBACP;oBACDD,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;wBAC/DA,EAAE;gBACN;aACD;QACH;QACAnB,YAAY;YACVgB,WAAW;gBACTa,OAAO;oBACLC,UAAU;gBACZ;YACF;QACF;QACA;YACEb,MAAM;YACNH,MAAM;YACNe,OAAO;gBACLC,UAAU;YACZ;YACAZ,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;gBAC/DA,EAAE;YACJY,YAAYxB;QACd;QACA;YACEU,MAAM;YACNH,MAAM;YACNe,OAAO;gBACLC,UAAU;YACZ;YACAZ,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;gBAC/DA,EAAE;QACN;QACA;YACEF,MAAM;YACNH,MAAM;YACNe,OAAO;gBACLC,UAAU;YACZ;YACAZ,OAAO,CAAC,EAAEC,CAAC,EAAE,GACX,+DAA+D;gBAC/DA,EAAE;YACJY,YAAYtB;QACd;QACA;YACEQ,MAAM;YACNH,MAAM;YACNe,OAAO;gBACLC,UAAU;YACZ;YACAC,YAAY1B;QACd;WACIC,mBACA;YACE;gBACEQ,MAAM;gBACNe,OAAO;oBACLC,UAAU;gBACZ;gBACAjB,QAAQ;oBACNhB,YAAY;wBACVS;oBACF;oBACAP,cAAc;wBACZO;oBACF;iBACD;YACH;SACD,GACD,EAAE;KACP;IAED,MAAM0B,aAA+B;QACnCC,MAAM;QACN9B,QAAQ;YACN+B,QAAQ/B,OAAOgC,OAAO;YACtBC,QAAQjC,OAAOgC,OAAO;YACtBE,MAAMlC,OAAOgC,OAAO;YACpBG,QAAQnC,OAAOgC,OAAO;QACxB;QACAN,OAAO;YACLU,gBAAgB;gBAAC;gBAAa;gBAAY;gBAAS;gBAAU;aAAS;YACtEC,aAAa,CAAC,EAAErB,CAAC,EAAE,GACjB,+DAA+D;gBAC/DA,EAAE;YACJS,OAAO;QACT;QACAf;QACAO,QAAQ;YACNC,QAAQ,CAAC,EAAEF,CAAC,EAAE,GACZ,+DAA+D;gBAC/DA,EAAE;YACJG,UAAU,CAAC,EAAEH,CAAC,EAAE,GACd,+DAA+D;gBAC/DA,EAAE;QACN;IACF;IAEA,OAAO;QAAE,GAAGa,UAAU;IAAC;AACzB,EAAC"}
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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({
|