mirror of
https://github.com/xtr-dev/payload-billing.git
synced 2025-12-10 02:43:24 +00:00
chore: Remove unused billing-related collections, types, and utility modules
- Drop `customers` collection and associated types (`types/index.ts`, `payload.ts`) - Remove generated `payload-types.ts` file - Clean up unused exports and dependencies across modules - Streamline codebase by eliminating redundant billing logic
This commit is contained in:
@@ -1,656 +0,0 @@
|
|||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
/**
|
|
||||||
* This file was automatically generated by Payload.
|
|
||||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
|
||||||
* and re-run `payload generate:types` to regenerate this file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supported timezones in IANA format.
|
|
||||||
*
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "supportedTimezones".
|
|
||||||
*/
|
|
||||||
export type SupportedTimezones =
|
|
||||||
| 'Pacific/Midway'
|
|
||||||
| 'Pacific/Niue'
|
|
||||||
| 'Pacific/Honolulu'
|
|
||||||
| 'Pacific/Rarotonga'
|
|
||||||
| 'America/Anchorage'
|
|
||||||
| 'Pacific/Gambier'
|
|
||||||
| 'America/Los_Angeles'
|
|
||||||
| 'America/Tijuana'
|
|
||||||
| 'America/Denver'
|
|
||||||
| 'America/Phoenix'
|
|
||||||
| 'America/Chicago'
|
|
||||||
| 'America/Guatemala'
|
|
||||||
| 'America/New_York'
|
|
||||||
| 'America/Bogota'
|
|
||||||
| 'America/Caracas'
|
|
||||||
| 'America/Santiago'
|
|
||||||
| 'America/Buenos_Aires'
|
|
||||||
| 'America/Sao_Paulo'
|
|
||||||
| 'Atlantic/South_Georgia'
|
|
||||||
| 'Atlantic/Azores'
|
|
||||||
| 'Atlantic/Cape_Verde'
|
|
||||||
| 'Europe/London'
|
|
||||||
| 'Europe/Berlin'
|
|
||||||
| 'Africa/Lagos'
|
|
||||||
| 'Europe/Athens'
|
|
||||||
| 'Africa/Cairo'
|
|
||||||
| 'Europe/Moscow'
|
|
||||||
| 'Asia/Riyadh'
|
|
||||||
| 'Asia/Dubai'
|
|
||||||
| 'Asia/Baku'
|
|
||||||
| 'Asia/Karachi'
|
|
||||||
| 'Asia/Tashkent'
|
|
||||||
| 'Asia/Calcutta'
|
|
||||||
| 'Asia/Dhaka'
|
|
||||||
| 'Asia/Almaty'
|
|
||||||
| 'Asia/Jakarta'
|
|
||||||
| 'Asia/Bangkok'
|
|
||||||
| 'Asia/Shanghai'
|
|
||||||
| 'Asia/Singapore'
|
|
||||||
| 'Asia/Tokyo'
|
|
||||||
| 'Asia/Seoul'
|
|
||||||
| 'Australia/Brisbane'
|
|
||||||
| 'Australia/Sydney'
|
|
||||||
| 'Pacific/Guam'
|
|
||||||
| 'Pacific/Noumea'
|
|
||||||
| 'Pacific/Auckland'
|
|
||||||
| 'Pacific/Fiji';
|
|
||||||
|
|
||||||
export interface Config {
|
|
||||||
auth: {
|
|
||||||
users: UserAuthOperations;
|
|
||||||
};
|
|
||||||
blocks: {};
|
|
||||||
collections: {
|
|
||||||
posts: Post;
|
|
||||||
media: Media;
|
|
||||||
payments: Payment;
|
|
||||||
customers: Customer;
|
|
||||||
invoices: Invoice;
|
|
||||||
refunds: Refund;
|
|
||||||
users: User;
|
|
||||||
'payload-locked-documents': PayloadLockedDocument;
|
|
||||||
'payload-preferences': PayloadPreference;
|
|
||||||
'payload-migrations': PayloadMigration;
|
|
||||||
};
|
|
||||||
collectionsJoins: {};
|
|
||||||
collectionsSelect: {
|
|
||||||
posts: PostsSelect<false> | PostsSelect<true>;
|
|
||||||
media: MediaSelect<false> | MediaSelect<true>;
|
|
||||||
payments: PaymentsSelect<false> | PaymentsSelect<true>;
|
|
||||||
customers: CustomersSelect<false> | CustomersSelect<true>;
|
|
||||||
invoices: InvoicesSelect<false> | InvoicesSelect<true>;
|
|
||||||
refunds: RefundsSelect<false> | RefundsSelect<true>;
|
|
||||||
users: UsersSelect<false> | UsersSelect<true>;
|
|
||||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
|
||||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
|
||||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
|
||||||
};
|
|
||||||
db: {
|
|
||||||
defaultIDType: number;
|
|
||||||
};
|
|
||||||
globals: {};
|
|
||||||
globalsSelect: {};
|
|
||||||
locale: null;
|
|
||||||
user: User & {
|
|
||||||
collection: 'users';
|
|
||||||
};
|
|
||||||
jobs: {
|
|
||||||
tasks: unknown;
|
|
||||||
workflows: unknown;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export interface UserAuthOperations {
|
|
||||||
forgotPassword: {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
login: {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
registerFirstUser: {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
unlock: {
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "posts".
|
|
||||||
*/
|
|
||||||
export interface Post {
|
|
||||||
id: number;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "media".
|
|
||||||
*/
|
|
||||||
export interface Media {
|
|
||||||
id: number;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
url?: string | null;
|
|
||||||
thumbnailURL?: string | null;
|
|
||||||
filename?: string | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
focalX?: number | null;
|
|
||||||
focalY?: number | null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payments".
|
|
||||||
*/
|
|
||||||
export interface Payment {
|
|
||||||
id: number;
|
|
||||||
provider: 'stripe' | 'mollie' | 'test';
|
|
||||||
/**
|
|
||||||
* The payment ID from the payment provider
|
|
||||||
*/
|
|
||||||
providerId: string;
|
|
||||||
status: 'pending' | 'processing' | 'succeeded' | 'failed' | 'canceled' | 'refunded' | 'partially_refunded';
|
|
||||||
/**
|
|
||||||
* Amount in cents (e.g., 2000 = $20.00)
|
|
||||||
*/
|
|
||||||
amount: number;
|
|
||||||
/**
|
|
||||||
* ISO 4217 currency code (e.g., USD, EUR)
|
|
||||||
*/
|
|
||||||
currency: string;
|
|
||||||
/**
|
|
||||||
* Payment description
|
|
||||||
*/
|
|
||||||
description?: string | null;
|
|
||||||
customer?: (number | null) | Customer;
|
|
||||||
invoice?: (number | null) | Invoice;
|
|
||||||
/**
|
|
||||||
* Additional metadata for the payment
|
|
||||||
*/
|
|
||||||
metadata?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
/**
|
|
||||||
* Raw data from the payment provider
|
|
||||||
*/
|
|
||||||
providerData?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
refunds?: (number | Refund)[] | null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "customers".
|
|
||||||
*/
|
|
||||||
export interface Customer {
|
|
||||||
id: number;
|
|
||||||
/**
|
|
||||||
* Customer email address
|
|
||||||
*/
|
|
||||||
email?: string | null;
|
|
||||||
/**
|
|
||||||
* Customer full name
|
|
||||||
*/
|
|
||||||
name?: string | null;
|
|
||||||
/**
|
|
||||||
* Customer phone number
|
|
||||||
*/
|
|
||||||
phone?: string | null;
|
|
||||||
address?: {
|
|
||||||
line1?: string | null;
|
|
||||||
line2?: string | null;
|
|
||||||
city?: string | null;
|
|
||||||
state?: string | null;
|
|
||||||
postal_code?: string | null;
|
|
||||||
/**
|
|
||||||
* ISO 3166-1 alpha-2 country code
|
|
||||||
*/
|
|
||||||
country?: string | null;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Customer IDs from payment providers
|
|
||||||
*/
|
|
||||||
providerIds?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
/**
|
|
||||||
* Additional customer metadata
|
|
||||||
*/
|
|
||||||
metadata?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
/**
|
|
||||||
* Customer payments
|
|
||||||
*/
|
|
||||||
payments?: (number | Payment)[] | null;
|
|
||||||
/**
|
|
||||||
* Customer invoices
|
|
||||||
*/
|
|
||||||
invoices?: (number | Invoice)[] | null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "invoices".
|
|
||||||
*/
|
|
||||||
export interface Invoice {
|
|
||||||
id: number;
|
|
||||||
/**
|
|
||||||
* Invoice number (e.g., INV-001)
|
|
||||||
*/
|
|
||||||
number: string;
|
|
||||||
customer: number | Customer;
|
|
||||||
status: 'draft' | 'open' | 'paid' | 'void' | 'uncollectible';
|
|
||||||
/**
|
|
||||||
* ISO 4217 currency code (e.g., USD, EUR)
|
|
||||||
*/
|
|
||||||
currency: string;
|
|
||||||
items: {
|
|
||||||
description: string;
|
|
||||||
quantity: number;
|
|
||||||
/**
|
|
||||||
* Amount in cents
|
|
||||||
*/
|
|
||||||
unitAmount: number;
|
|
||||||
/**
|
|
||||||
* Calculated: quantity × unitAmount
|
|
||||||
*/
|
|
||||||
totalAmount?: number | null;
|
|
||||||
id?: string | null;
|
|
||||||
}[];
|
|
||||||
/**
|
|
||||||
* Sum of all line items
|
|
||||||
*/
|
|
||||||
subtotal?: number | null;
|
|
||||||
/**
|
|
||||||
* Tax amount in cents
|
|
||||||
*/
|
|
||||||
taxAmount?: number | null;
|
|
||||||
/**
|
|
||||||
* Total amount (subtotal + tax)
|
|
||||||
*/
|
|
||||||
amount?: number | null;
|
|
||||||
dueDate?: string | null;
|
|
||||||
paidAt?: string | null;
|
|
||||||
payment?: (number | null) | Payment;
|
|
||||||
/**
|
|
||||||
* Internal notes
|
|
||||||
*/
|
|
||||||
notes?: string | null;
|
|
||||||
/**
|
|
||||||
* Additional invoice metadata
|
|
||||||
*/
|
|
||||||
metadata?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "refunds".
|
|
||||||
*/
|
|
||||||
export interface Refund {
|
|
||||||
id: number;
|
|
||||||
/**
|
|
||||||
* The refund ID from the payment provider
|
|
||||||
*/
|
|
||||||
providerId: string;
|
|
||||||
payment: number | Payment;
|
|
||||||
status: 'pending' | 'processing' | 'succeeded' | 'failed' | 'canceled';
|
|
||||||
/**
|
|
||||||
* Refund amount in cents
|
|
||||||
*/
|
|
||||||
amount: number;
|
|
||||||
/**
|
|
||||||
* ISO 4217 currency code (e.g., USD, EUR)
|
|
||||||
*/
|
|
||||||
currency: string;
|
|
||||||
/**
|
|
||||||
* Reason for the refund
|
|
||||||
*/
|
|
||||||
reason?: ('duplicate' | 'fraudulent' | 'requested_by_customer' | 'other') | null;
|
|
||||||
/**
|
|
||||||
* Additional details about the refund
|
|
||||||
*/
|
|
||||||
description?: string | null;
|
|
||||||
/**
|
|
||||||
* Additional refund metadata
|
|
||||||
*/
|
|
||||||
metadata?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
/**
|
|
||||||
* Raw data from the payment provider
|
|
||||||
*/
|
|
||||||
providerData?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "users".
|
|
||||||
*/
|
|
||||||
export interface User {
|
|
||||||
id: number;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
email: string;
|
|
||||||
resetPasswordToken?: string | null;
|
|
||||||
resetPasswordExpiration?: string | null;
|
|
||||||
salt?: string | null;
|
|
||||||
hash?: string | null;
|
|
||||||
loginAttempts?: number | null;
|
|
||||||
lockUntil?: string | null;
|
|
||||||
password?: string | null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-locked-documents".
|
|
||||||
*/
|
|
||||||
export interface PayloadLockedDocument {
|
|
||||||
id: number;
|
|
||||||
document?:
|
|
||||||
| ({
|
|
||||||
relationTo: 'posts';
|
|
||||||
value: number | Post;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'media';
|
|
||||||
value: number | Media;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'payments';
|
|
||||||
value: number | Payment;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'customers';
|
|
||||||
value: number | Customer;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'invoices';
|
|
||||||
value: number | Invoice;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'refunds';
|
|
||||||
value: number | Refund;
|
|
||||||
} | null)
|
|
||||||
| ({
|
|
||||||
relationTo: 'users';
|
|
||||||
value: number | User;
|
|
||||||
} | null);
|
|
||||||
globalSlug?: string | null;
|
|
||||||
user: {
|
|
||||||
relationTo: 'users';
|
|
||||||
value: number | User;
|
|
||||||
};
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-preferences".
|
|
||||||
*/
|
|
||||||
export interface PayloadPreference {
|
|
||||||
id: number;
|
|
||||||
user: {
|
|
||||||
relationTo: 'users';
|
|
||||||
value: number | User;
|
|
||||||
};
|
|
||||||
key?: string | null;
|
|
||||||
value?:
|
|
||||||
| {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
| unknown[]
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-migrations".
|
|
||||||
*/
|
|
||||||
export interface PayloadMigration {
|
|
||||||
id: number;
|
|
||||||
name?: string | null;
|
|
||||||
batch?: number | null;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "posts_select".
|
|
||||||
*/
|
|
||||||
export interface PostsSelect<T extends boolean = true> {
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "media_select".
|
|
||||||
*/
|
|
||||||
export interface MediaSelect<T extends boolean = true> {
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
url?: T;
|
|
||||||
thumbnailURL?: T;
|
|
||||||
filename?: T;
|
|
||||||
mimeType?: T;
|
|
||||||
filesize?: T;
|
|
||||||
width?: T;
|
|
||||||
height?: T;
|
|
||||||
focalX?: T;
|
|
||||||
focalY?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payments_select".
|
|
||||||
*/
|
|
||||||
export interface PaymentsSelect<T extends boolean = true> {
|
|
||||||
provider?: T;
|
|
||||||
providerId?: T;
|
|
||||||
status?: T;
|
|
||||||
amount?: T;
|
|
||||||
currency?: T;
|
|
||||||
description?: T;
|
|
||||||
customer?: T;
|
|
||||||
invoice?: T;
|
|
||||||
metadata?: T;
|
|
||||||
providerData?: T;
|
|
||||||
refunds?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "customers_select".
|
|
||||||
*/
|
|
||||||
export interface CustomersSelect<T extends boolean = true> {
|
|
||||||
email?: T;
|
|
||||||
name?: T;
|
|
||||||
phone?: T;
|
|
||||||
address?:
|
|
||||||
| T
|
|
||||||
| {
|
|
||||||
line1?: T;
|
|
||||||
line2?: T;
|
|
||||||
city?: T;
|
|
||||||
state?: T;
|
|
||||||
postal_code?: T;
|
|
||||||
country?: T;
|
|
||||||
};
|
|
||||||
providerIds?: T;
|
|
||||||
metadata?: T;
|
|
||||||
payments?: T;
|
|
||||||
invoices?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "invoices_select".
|
|
||||||
*/
|
|
||||||
export interface InvoicesSelect<T extends boolean = true> {
|
|
||||||
number?: T;
|
|
||||||
customer?: T;
|
|
||||||
status?: T;
|
|
||||||
currency?: T;
|
|
||||||
items?:
|
|
||||||
| T
|
|
||||||
| {
|
|
||||||
description?: T;
|
|
||||||
quantity?: T;
|
|
||||||
unitAmount?: T;
|
|
||||||
totalAmount?: T;
|
|
||||||
id?: T;
|
|
||||||
};
|
|
||||||
subtotal?: T;
|
|
||||||
taxAmount?: T;
|
|
||||||
amount?: T;
|
|
||||||
dueDate?: T;
|
|
||||||
paidAt?: T;
|
|
||||||
payment?: T;
|
|
||||||
notes?: T;
|
|
||||||
metadata?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "refunds_select".
|
|
||||||
*/
|
|
||||||
export interface RefundsSelect<T extends boolean = true> {
|
|
||||||
providerId?: T;
|
|
||||||
payment?: T;
|
|
||||||
status?: T;
|
|
||||||
amount?: T;
|
|
||||||
currency?: T;
|
|
||||||
reason?: T;
|
|
||||||
description?: T;
|
|
||||||
metadata?: T;
|
|
||||||
providerData?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "users_select".
|
|
||||||
*/
|
|
||||||
export interface UsersSelect<T extends boolean = true> {
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
email?: T;
|
|
||||||
resetPasswordToken?: T;
|
|
||||||
resetPasswordExpiration?: T;
|
|
||||||
salt?: T;
|
|
||||||
hash?: T;
|
|
||||||
loginAttempts?: T;
|
|
||||||
lockUntil?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-locked-documents_select".
|
|
||||||
*/
|
|
||||||
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
|
|
||||||
document?: T;
|
|
||||||
globalSlug?: T;
|
|
||||||
user?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-preferences_select".
|
|
||||||
*/
|
|
||||||
export interface PayloadPreferencesSelect<T extends boolean = true> {
|
|
||||||
user?: T;
|
|
||||||
key?: T;
|
|
||||||
value?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "payload-migrations_select".
|
|
||||||
*/
|
|
||||||
export interface PayloadMigrationsSelect<T extends boolean = true> {
|
|
||||||
name?: T;
|
|
||||||
batch?: T;
|
|
||||||
updatedAt?: T;
|
|
||||||
createdAt?: T;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "auth".
|
|
||||||
*/
|
|
||||||
export interface Auth {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare module 'payload' {
|
|
||||||
export interface GeneratedTypes extends Config {}
|
|
||||||
}
|
|
||||||
@@ -44,6 +44,7 @@ export default [
|
|||||||
'perfectionist/sort-switch-case': 'off',
|
'perfectionist/sort-switch-case': 'off',
|
||||||
'perfectionist/sort-union-types': 'off',
|
'perfectionist/sort-union-types': 'off',
|
||||||
'perfectionist/sort-variable-declarations': 'off',
|
'perfectionist/sort-variable-declarations': 'off',
|
||||||
|
'perfectionist/sort-intersection-types': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
import type { CollectionConfig } from 'payload'
|
|
||||||
|
|
||||||
import type {
|
|
||||||
AccessArgs,
|
|
||||||
CollectionAfterChangeHook,
|
|
||||||
CollectionBeforeChangeHook,
|
|
||||||
CustomerData,
|
|
||||||
CustomerDocument
|
|
||||||
} from '../types/payload'
|
|
||||||
|
|
||||||
export function createCustomersCollection(slug: string = 'customers'): CollectionConfig {
|
|
||||||
return {
|
|
||||||
slug,
|
|
||||||
access: {
|
|
||||||
create: ({ req: { user } }: AccessArgs) => !!user,
|
|
||||||
delete: ({ req: { user } }: AccessArgs) => !!user,
|
|
||||||
read: ({ req: { user } }: AccessArgs) => !!user,
|
|
||||||
update: ({ req: { user } }: AccessArgs) => !!user,
|
|
||||||
},
|
|
||||||
admin: {
|
|
||||||
defaultColumns: ['email', 'name', 'createdAt'],
|
|
||||||
group: 'Billing',
|
|
||||||
useAsTitle: 'email',
|
|
||||||
},
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'email',
|
|
||||||
type: 'email',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer email address',
|
|
||||||
},
|
|
||||||
index: true,
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'text',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer full name',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'phone',
|
|
||||||
type: 'text',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer phone number',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'address',
|
|
||||||
type: 'group',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'line1',
|
|
||||||
type: 'text',
|
|
||||||
label: 'Address Line 1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'line2',
|
|
||||||
type: 'text',
|
|
||||||
label: 'Address Line 2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'city',
|
|
||||||
type: 'text',
|
|
||||||
label: 'City',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'state',
|
|
||||||
type: 'text',
|
|
||||||
label: 'State/Province',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'postalCode',
|
|
||||||
type: 'text',
|
|
||||||
label: 'Postal Code',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'country',
|
|
||||||
type: 'text',
|
|
||||||
admin: {
|
|
||||||
description: 'ISO 3166-1 alpha-2 country code',
|
|
||||||
},
|
|
||||||
label: 'Country',
|
|
||||||
maxLength: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'providerIds',
|
|
||||||
type: 'json',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer IDs from payment providers',
|
|
||||||
readOnly: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'metadata',
|
|
||||||
type: 'json',
|
|
||||||
admin: {
|
|
||||||
description: 'Additional customer metadata',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'payments',
|
|
||||||
type: 'relationship',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer payments',
|
|
||||||
readOnly: true,
|
|
||||||
},
|
|
||||||
hasMany: true,
|
|
||||||
relationTo: 'payments',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'invoices',
|
|
||||||
type: 'relationship',
|
|
||||||
admin: {
|
|
||||||
description: 'Customer invoices',
|
|
||||||
readOnly: true,
|
|
||||||
},
|
|
||||||
hasMany: true,
|
|
||||||
relationTo: 'invoices',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hooks: {
|
|
||||||
afterChange: [
|
|
||||||
({ doc, operation, req }: CollectionAfterChangeHook<CustomerDocument>) => {
|
|
||||||
if (operation === 'create') {
|
|
||||||
req.payload.logger.info(`Customer created: ${doc.id} (${doc.email})`)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
beforeChange: [
|
|
||||||
({ data, operation }: CollectionBeforeChangeHook<CustomerData>) => {
|
|
||||||
if (operation === 'create' || operation === 'update') {
|
|
||||||
// Normalize country code
|
|
||||||
if (data.address?.country) {
|
|
||||||
data.address.country = data.address.country.toUpperCase()
|
|
||||||
if (!/^[A-Z]{2}$/.test(data.address.country)) {
|
|
||||||
throw new Error('Country must be a 2-letter ISO code')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
timestamps: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import type { CollectionConfig } from 'payload'
|
import {
|
||||||
|
|
||||||
import type {
|
|
||||||
AccessArgs,
|
AccessArgs,
|
||||||
CollectionAfterChangeHook,
|
CollectionAfterChangeHook,
|
||||||
CollectionBeforeChangeHook,
|
CollectionBeforeChangeHook,
|
||||||
CollectionBeforeValidateHook,
|
CollectionBeforeValidateHook,
|
||||||
InvoiceData,
|
CollectionConfig,
|
||||||
InvoiceDocument,
|
} from 'payload'
|
||||||
InvoiceItemData
|
import { CustomerInfoExtractor } from '@/plugin/config'
|
||||||
} from '../types/payload'
|
import { Invoice } from '@/plugin/types'
|
||||||
import type { CustomerInfoExtractor } from '../types'
|
|
||||||
|
|
||||||
export function createInvoicesCollection(
|
export function createInvoicesCollection(
|
||||||
slug: string = 'invoices',
|
slug: string = 'invoices',
|
||||||
@@ -281,7 +278,7 @@ export function createInvoicesCollection(
|
|||||||
name: 'paidAt',
|
name: 'paidAt',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (data: InvoiceData) => data.status === 'paid',
|
condition: (data) => data.status === 'paid',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -289,7 +286,7 @@ export function createInvoicesCollection(
|
|||||||
name: 'payment',
|
name: 'payment',
|
||||||
type: 'relationship',
|
type: 'relationship',
|
||||||
admin: {
|
admin: {
|
||||||
condition: (data: InvoiceData) => data.status === 'paid',
|
condition: (data) => data.status === 'paid',
|
||||||
position: 'sidebar',
|
position: 'sidebar',
|
||||||
},
|
},
|
||||||
relationTo: 'payments',
|
relationTo: 'payments',
|
||||||
@@ -311,14 +308,14 @@ export function createInvoicesCollection(
|
|||||||
],
|
],
|
||||||
hooks: {
|
hooks: {
|
||||||
afterChange: [
|
afterChange: [
|
||||||
({ doc, operation, req }: CollectionAfterChangeHook<InvoiceDocument>) => {
|
({ doc, operation, req }) => {
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
req.payload.logger.info(`Invoice created: ${doc.number}`)
|
req.payload.logger.info(`Invoice created: ${doc.number}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
] satisfies CollectionAfterChangeHook<Invoice>[],
|
||||||
beforeChange: [
|
beforeChange: [
|
||||||
async ({ data, operation, req, originalDoc }: CollectionBeforeChangeHook<InvoiceData>) => {
|
async ({ data, operation, req, originalDoc }) => {
|
||||||
// Sync customer info from relationship if extractor is provided
|
// Sync customer info from relationship if extractor is provided
|
||||||
if (customerCollectionSlug && customerInfoExtractor && data.customer) {
|
if (customerCollectionSlug && customerInfoExtractor && data.customer) {
|
||||||
// Check if customer changed or this is a new invoice
|
// Check if customer changed or this is a new invoice
|
||||||
@@ -329,7 +326,7 @@ export function createInvoicesCollection(
|
|||||||
try {
|
try {
|
||||||
// Fetch the customer data
|
// Fetch the customer data
|
||||||
const customer = await req.payload.findByID({
|
const customer = await req.payload.findByID({
|
||||||
collection: customerCollectionSlug,
|
collection: customerCollectionSlug as any,
|
||||||
id: data.customer,
|
id: data.customer,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -383,9 +380,9 @@ export function createInvoicesCollection(
|
|||||||
data.paidAt = new Date().toISOString()
|
data.paidAt = new Date().toISOString()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
] satisfies CollectionBeforeChangeHook<Invoice>[],
|
||||||
beforeValidate: [
|
beforeValidate: [
|
||||||
({ data }: CollectionBeforeValidateHook<InvoiceData>) => {
|
({ data }) => {
|
||||||
if (!data) return
|
if (!data) return
|
||||||
|
|
||||||
// If using extractor, customer relationship is required
|
// If using extractor, customer relationship is required
|
||||||
@@ -406,14 +403,14 @@ export function createInvoicesCollection(
|
|||||||
|
|
||||||
if (data && data.items && Array.isArray(data.items)) {
|
if (data && data.items && Array.isArray(data.items)) {
|
||||||
// Calculate totals for each line item
|
// Calculate totals for each line item
|
||||||
data.items = data.items.map((item: InvoiceItemData) => ({
|
data.items = data.items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
totalAmount: (item.quantity || 0) * (item.unitAmount || 0),
|
totalAmount: (item.quantity || 0) * (item.unitAmount || 0),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Calculate subtotal
|
// Calculate subtotal
|
||||||
data.subtotal = data.items.reduce(
|
data.subtotal = data.items.reduce(
|
||||||
(sum: number, item: InvoiceItemData) => sum + (item.totalAmount || 0),
|
(sum: number, item) => sum + (item.totalAmount || 0),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -421,7 +418,7 @@ export function createInvoicesCollection(
|
|||||||
data.amount = (data.subtotal || 0) + (data.taxAmount || 0)
|
data.amount = (data.subtotal || 0) + (data.taxAmount || 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
] satisfies CollectionBeforeValidateHook<Invoice>[],
|
||||||
},
|
},
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
import type { CollectionConfig } from 'payload'
|
import { AccessArgs, CollectionAfterChangeHook, CollectionBeforeChangeHook, CollectionConfig } from 'payload'
|
||||||
|
import { Payment } from '@/plugin/types'
|
||||||
import type {
|
|
||||||
AccessArgs,
|
|
||||||
CollectionAfterChangeHook,
|
|
||||||
CollectionBeforeChangeHook,
|
|
||||||
PaymentData,
|
|
||||||
PaymentDocument
|
|
||||||
} from '../types/payload'
|
|
||||||
|
|
||||||
export function createPaymentsCollection(slug: string = 'payments'): CollectionConfig {
|
export function createPaymentsCollection(slug: string = 'payments'): CollectionConfig {
|
||||||
return {
|
return {
|
||||||
@@ -131,15 +124,8 @@ export function createPaymentsCollection(slug: string = 'payments'): CollectionC
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
hooks: {
|
hooks: {
|
||||||
afterChange: [
|
|
||||||
({ doc, operation, req }: CollectionAfterChangeHook<PaymentDocument>) => {
|
|
||||||
if (operation === 'create') {
|
|
||||||
req.payload.logger.info(`Payment created: ${doc.id} (${doc.provider})`)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
beforeChange: [
|
beforeChange: [
|
||||||
({ data, operation }: CollectionBeforeChangeHook<PaymentData>) => {
|
({ data, operation }) => {
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
// Validate amount format
|
// Validate amount format
|
||||||
if (data.amount && !Number.isInteger(data.amount)) {
|
if (data.amount && !Number.isInteger(data.amount)) {
|
||||||
@@ -155,7 +141,7 @@ export function createPaymentsCollection(slug: string = 'payments'): CollectionC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
] satisfies CollectionBeforeChangeHook<Payment>[],
|
||||||
},
|
},
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
}
|
}
|
||||||
|
|||||||
95
src/index.ts
95
src/index.ts
@@ -1,98 +1,3 @@
|
|||||||
import type { Config } from 'payload'
|
|
||||||
|
|
||||||
import type { BillingPluginConfig, CustomerInfoExtractor } from './types'
|
|
||||||
|
|
||||||
import { createCustomersCollection } from './collections/customers'
|
|
||||||
import { createInvoicesCollection } from './collections/invoices'
|
|
||||||
import { createPaymentsCollection } from './collections/payments'
|
|
||||||
import { createRefundsCollection } from './collections/refunds'
|
|
||||||
|
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|
||||||
// Default customer info extractor for the built-in customer collection
|
|
||||||
export const defaultCustomerInfoExtractor: CustomerInfoExtractor = (customer) => {
|
|
||||||
return {
|
|
||||||
name: customer.name || '',
|
|
||||||
email: customer.email || '',
|
|
||||||
phone: customer.phone,
|
|
||||||
company: customer.company,
|
|
||||||
taxId: customer.taxId,
|
|
||||||
billingAddress: customer.address ? {
|
|
||||||
line1: customer.address.line1 || '',
|
|
||||||
line2: customer.address.line2,
|
|
||||||
city: customer.address.city || '',
|
|
||||||
state: customer.address.state,
|
|
||||||
postalCode: customer.address.postalCode || '',
|
|
||||||
country: customer.address.country || '',
|
|
||||||
} : undefined,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const billingPlugin = (pluginConfig: BillingPluginConfig = {}) => (config: Config): Config => {
|
|
||||||
if (pluginConfig.disabled) {
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize collections
|
|
||||||
if (!config.collections) {
|
|
||||||
config.collections = []
|
|
||||||
}
|
|
||||||
|
|
||||||
const customerSlug = pluginConfig.collections?.customers || 'customers'
|
|
||||||
|
|
||||||
config.collections.push(
|
|
||||||
createPaymentsCollection(pluginConfig.collections?.payments || 'payments'),
|
|
||||||
createCustomersCollection(customerSlug),
|
|
||||||
createInvoicesCollection(
|
|
||||||
pluginConfig.collections?.invoices || 'invoices',
|
|
||||||
pluginConfig.collections?.customerRelation !== false ? customerSlug : undefined,
|
|
||||||
pluginConfig.customerInfoExtractor
|
|
||||||
),
|
|
||||||
createRefundsCollection(pluginConfig.collections?.refunds || 'refunds'),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Initialize endpoints
|
|
||||||
if (!config.endpoints) {
|
|
||||||
config.endpoints = []
|
|
||||||
}
|
|
||||||
|
|
||||||
config.endpoints?.push(
|
|
||||||
// Webhook endpoints
|
|
||||||
{
|
|
||||||
handler: (_req) => {
|
|
||||||
try {
|
|
||||||
const provider = null
|
|
||||||
if (!provider) {
|
|
||||||
return Response.json({ error: 'Provider not found' }, { status: 404 })
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Process webhook event and update database
|
|
||||||
|
|
||||||
return Response.json({ received: true })
|
|
||||||
} catch (error) {
|
|
||||||
// TODO: Use proper logger instead of console
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error('[BILLING] Webhook error:', error)
|
|
||||||
return Response.json({ error: 'Webhook processing failed' }, { status: 400 })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
method: 'post',
|
|
||||||
path: '/billing/webhooks/:provider'
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Initialize providers and onInit hook
|
|
||||||
const incomingOnInit = config.onInit
|
|
||||||
|
|
||||||
config.onInit = async (payload) => {
|
|
||||||
// Execute any existing onInit functions first
|
|
||||||
if (incomingOnInit) {
|
|
||||||
await incomingOnInit(payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
export default billingPlugin
|
|
||||||
|
|||||||
76
src/plugin/config.ts
Normal file
76
src/plugin/config.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
export const defaults = {
|
||||||
|
paymentsCollection: 'payments'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider configurations
|
||||||
|
export interface StripeConfig {
|
||||||
|
apiVersion?: string
|
||||||
|
publishableKey: string
|
||||||
|
secretKey: string
|
||||||
|
webhookEndpointSecret: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MollieConfig {
|
||||||
|
apiKey: string
|
||||||
|
testMode?: boolean
|
||||||
|
webhookUrl: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestProviderConfig {
|
||||||
|
autoComplete?: boolean
|
||||||
|
defaultDelay?: number
|
||||||
|
enabled: boolean
|
||||||
|
failureRate?: number
|
||||||
|
simulateFailures?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customer info extractor callback type
|
||||||
|
export interface CustomerInfoExtractor {
|
||||||
|
(customer: any): {
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
phone?: string
|
||||||
|
company?: string
|
||||||
|
taxId?: string
|
||||||
|
billingAddress?: {
|
||||||
|
line1: string
|
||||||
|
line2?: string
|
||||||
|
city: string
|
||||||
|
state?: string
|
||||||
|
postalCode: string
|
||||||
|
country: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin configuration
|
||||||
|
export interface BillingPluginConfig {
|
||||||
|
admin?: {
|
||||||
|
customComponents?: boolean
|
||||||
|
dashboard?: boolean
|
||||||
|
}
|
||||||
|
collections?: {
|
||||||
|
customerRelation?: boolean | string // false to disable, string for custom collection slug
|
||||||
|
customers?: string
|
||||||
|
invoices?: string
|
||||||
|
payments?: string
|
||||||
|
refunds?: string
|
||||||
|
}
|
||||||
|
customerInfoExtractor?: CustomerInfoExtractor // Callback to extract customer info from relationship
|
||||||
|
disabled?: boolean
|
||||||
|
providers?: {
|
||||||
|
mollie?: MollieConfig
|
||||||
|
stripe?: StripeConfig
|
||||||
|
test?: TestProviderConfig
|
||||||
|
}
|
||||||
|
webhooks?: {
|
||||||
|
basePath?: string
|
||||||
|
cors?: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin type
|
||||||
|
export interface BillingPluginOptions extends BillingPluginConfig {
|
||||||
|
disabled?: boolean
|
||||||
|
}
|
||||||
70
src/plugin/index.ts
Normal file
70
src/plugin/index.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import type { Config } from 'payload'
|
||||||
|
import { createInvoicesCollection, createPaymentsCollection, createRefundsCollection } from '@/collections'
|
||||||
|
import { BillingPluginConfig } from '@/plugin/config'
|
||||||
|
|
||||||
|
export const billingPlugin = (pluginConfig: BillingPluginConfig = {}) => (config: Config): Config => {
|
||||||
|
if (pluginConfig.disabled) {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize collections
|
||||||
|
if (!config.collections) {
|
||||||
|
config.collections = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerSlug = pluginConfig.collections?.customers || 'customers'
|
||||||
|
|
||||||
|
config.collections.push(
|
||||||
|
createPaymentsCollection(pluginConfig.collections?.payments || 'payments'),
|
||||||
|
createInvoicesCollection(
|
||||||
|
pluginConfig.collections?.invoices || 'invoices',
|
||||||
|
pluginConfig.collections?.customerRelation !== false ? customerSlug : undefined,
|
||||||
|
pluginConfig.customerInfoExtractor
|
||||||
|
),
|
||||||
|
createRefundsCollection(pluginConfig.collections?.refunds || 'refunds'),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialize endpoints
|
||||||
|
if (!config.endpoints) {
|
||||||
|
config.endpoints = []
|
||||||
|
}
|
||||||
|
|
||||||
|
config.endpoints?.push(
|
||||||
|
// Webhook endpoints
|
||||||
|
{
|
||||||
|
handler: (_req) => {
|
||||||
|
try {
|
||||||
|
const provider = null
|
||||||
|
if (!provider) {
|
||||||
|
return Response.json({ error: 'Provider not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Process webhook event and update database
|
||||||
|
|
||||||
|
return Response.json({ received: true })
|
||||||
|
} catch (error) {
|
||||||
|
// TODO: Use proper logger instead of console
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('[BILLING] Webhook error:', error)
|
||||||
|
return Response.json({ error: 'Webhook processing failed' }, { status: 400 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
method: 'post',
|
||||||
|
path: '/billing/webhooks/:provider'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialize providers and onInit hook
|
||||||
|
const incomingOnInit = config.onInit
|
||||||
|
|
||||||
|
config.onInit = async (payload) => {
|
||||||
|
// Execute any existing onInit functions first
|
||||||
|
if (incomingOnInit) {
|
||||||
|
await incomingOnInit(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
export default billingPlugin
|
||||||
168
src/plugin/types.ts
Normal file
168
src/plugin/types.ts
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { Customer, Refund } from '../../dev/payload-types'
|
||||||
|
|
||||||
|
export type Id = string | number
|
||||||
|
|
||||||
|
export interface Payment {
|
||||||
|
id: Id;
|
||||||
|
provider: 'stripe' | 'mollie' | 'test';
|
||||||
|
/**
|
||||||
|
* The payment ID from the payment provider
|
||||||
|
*/
|
||||||
|
providerId: Id;
|
||||||
|
status: 'pending' | 'processing' | 'succeeded' | 'failed' | 'canceled' | 'refunded' | 'partially_refunded';
|
||||||
|
/**
|
||||||
|
* Amount in cents (e.g., 2000 = $20.00)
|
||||||
|
*/
|
||||||
|
amount: number;
|
||||||
|
/**
|
||||||
|
* ISO 4217 currency code (e.g., USD, EUR)
|
||||||
|
*/
|
||||||
|
currency: string;
|
||||||
|
/**
|
||||||
|
* Payment description
|
||||||
|
*/
|
||||||
|
description?: string | null;
|
||||||
|
customer?: (Id | null) | Customer;
|
||||||
|
invoice?: (Id | null) | Invoice;
|
||||||
|
/**
|
||||||
|
* Additional metadata for the payment
|
||||||
|
*/
|
||||||
|
metadata?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
/**
|
||||||
|
* Raw data from the payment provider
|
||||||
|
*/
|
||||||
|
providerData?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
refunds?: (number | Refund)[] | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Invoice {
|
||||||
|
id: Id;
|
||||||
|
/**
|
||||||
|
* Invoice number (e.g., INV-001)
|
||||||
|
*/
|
||||||
|
number: string;
|
||||||
|
/**
|
||||||
|
* Link to customer record (optional)
|
||||||
|
*/
|
||||||
|
customer?: (Id | null) | Customer;
|
||||||
|
/**
|
||||||
|
* Customer billing information (auto-populated from customer relationship)
|
||||||
|
*/
|
||||||
|
customerInfo?: {
|
||||||
|
/**
|
||||||
|
* Customer name
|
||||||
|
*/
|
||||||
|
name?: string | null;
|
||||||
|
/**
|
||||||
|
* Customer email address
|
||||||
|
*/
|
||||||
|
email?: string | null;
|
||||||
|
/**
|
||||||
|
* Customer phone number
|
||||||
|
*/
|
||||||
|
phone?: string | null;
|
||||||
|
/**
|
||||||
|
* Company name (optional)
|
||||||
|
*/
|
||||||
|
company?: string | null;
|
||||||
|
/**
|
||||||
|
* Tax ID or VAT number
|
||||||
|
*/
|
||||||
|
taxId?: string | null;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Billing address (auto-populated from customer relationship)
|
||||||
|
*/
|
||||||
|
billingAddress?: {
|
||||||
|
/**
|
||||||
|
* Address line 1
|
||||||
|
*/
|
||||||
|
line1?: string | null;
|
||||||
|
/**
|
||||||
|
* Address line 2
|
||||||
|
*/
|
||||||
|
line2?: string | null;
|
||||||
|
city?: string | null;
|
||||||
|
/**
|
||||||
|
* State or province
|
||||||
|
*/
|
||||||
|
state?: string | null;
|
||||||
|
/**
|
||||||
|
* Postal or ZIP code
|
||||||
|
*/
|
||||||
|
postalCode?: string | null;
|
||||||
|
/**
|
||||||
|
* Country code (e.g., US, GB)
|
||||||
|
*/
|
||||||
|
country?: string | null;
|
||||||
|
};
|
||||||
|
status: 'draft' | 'open' | 'paid' | 'void' | 'uncollectible';
|
||||||
|
/**
|
||||||
|
* ISO 4217 currency code (e.g., USD, EUR)
|
||||||
|
*/
|
||||||
|
currency: string;
|
||||||
|
items: {
|
||||||
|
description: string;
|
||||||
|
quantity: number;
|
||||||
|
/**
|
||||||
|
* Amount in cents
|
||||||
|
*/
|
||||||
|
unitAmount: number;
|
||||||
|
/**
|
||||||
|
* Calculated: quantity × unitAmount
|
||||||
|
*/
|
||||||
|
totalAmount?: number | null;
|
||||||
|
id?: Id | null;
|
||||||
|
}[];
|
||||||
|
/**
|
||||||
|
* Sum of all line items
|
||||||
|
*/
|
||||||
|
subtotal?: number | null;
|
||||||
|
/**
|
||||||
|
* Tax amount in cents
|
||||||
|
*/
|
||||||
|
taxAmount?: number | null;
|
||||||
|
/**
|
||||||
|
* Total amount (subtotal + tax)
|
||||||
|
*/
|
||||||
|
amount?: number | null;
|
||||||
|
dueDate?: string | null;
|
||||||
|
paidAt?: string | null;
|
||||||
|
payment?: (number | null) | Payment;
|
||||||
|
/**
|
||||||
|
* Internal notes
|
||||||
|
*/
|
||||||
|
notes?: string | null;
|
||||||
|
/**
|
||||||
|
* Additional invoice metadata
|
||||||
|
*/
|
||||||
|
metadata?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
import type { Config } from 'payload'
|
|
||||||
|
|
||||||
// Base payment provider interface
|
|
||||||
export interface PaymentProvider {
|
|
||||||
cancelPayment(id: string): Promise<Payment>
|
|
||||||
createPayment(options: CreatePaymentOptions): Promise<Payment>
|
|
||||||
handleWebhook(request: Request, signature?: string): Promise<WebhookEvent>
|
|
||||||
name: string
|
|
||||||
refundPayment(id: string, amount?: number): Promise<Refund>
|
|
||||||
retrievePayment(id: string): Promise<Payment>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payment types
|
|
||||||
export interface CreatePaymentOptions {
|
|
||||||
amount: number
|
|
||||||
cancelUrl?: string
|
|
||||||
currency: string
|
|
||||||
customer?: string
|
|
||||||
description?: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
returnUrl?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Payment {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
customer?: string
|
|
||||||
description?: string
|
|
||||||
id: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
provider: string
|
|
||||||
providerData?: Record<string, unknown>
|
|
||||||
status: PaymentStatus
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Refund {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
id: string
|
|
||||||
paymentId: string
|
|
||||||
providerData?: Record<string, unknown>
|
|
||||||
reason?: string
|
|
||||||
status: RefundStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebhookEvent {
|
|
||||||
data: Record<string, unknown>
|
|
||||||
id: string
|
|
||||||
provider: string
|
|
||||||
type: string
|
|
||||||
verified: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status enums
|
|
||||||
export type PaymentStatus =
|
|
||||||
| 'canceled'
|
|
||||||
| 'failed'
|
|
||||||
| 'partially_refunded'
|
|
||||||
| 'pending'
|
|
||||||
| 'processing'
|
|
||||||
| 'refunded'
|
|
||||||
| 'succeeded'
|
|
||||||
|
|
||||||
export type RefundStatus =
|
|
||||||
| 'canceled'
|
|
||||||
| 'failed'
|
|
||||||
| 'pending'
|
|
||||||
| 'processing'
|
|
||||||
| 'succeeded'
|
|
||||||
|
|
||||||
// Provider configurations
|
|
||||||
export interface StripeConfig {
|
|
||||||
apiVersion?: string
|
|
||||||
publishableKey: string
|
|
||||||
secretKey: string
|
|
||||||
webhookEndpointSecret: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MollieConfig {
|
|
||||||
apiKey: string
|
|
||||||
testMode?: boolean
|
|
||||||
webhookUrl: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TestProviderConfig {
|
|
||||||
autoComplete?: boolean
|
|
||||||
defaultDelay?: number
|
|
||||||
enabled: boolean
|
|
||||||
failureRate?: number
|
|
||||||
simulateFailures?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// Customer info extractor callback type
|
|
||||||
export interface CustomerInfoExtractor {
|
|
||||||
(customer: any): {
|
|
||||||
name: string
|
|
||||||
email: string
|
|
||||||
phone?: string
|
|
||||||
company?: string
|
|
||||||
taxId?: string
|
|
||||||
billingAddress?: {
|
|
||||||
line1: string
|
|
||||||
line2?: string
|
|
||||||
city: string
|
|
||||||
state?: string
|
|
||||||
postalCode: string
|
|
||||||
country: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin configuration
|
|
||||||
export interface BillingPluginConfig {
|
|
||||||
admin?: {
|
|
||||||
customComponents?: boolean
|
|
||||||
dashboard?: boolean
|
|
||||||
}
|
|
||||||
collections?: {
|
|
||||||
customerRelation?: boolean | string // false to disable, string for custom collection slug
|
|
||||||
customers?: string
|
|
||||||
invoices?: string
|
|
||||||
payments?: string
|
|
||||||
refunds?: string
|
|
||||||
}
|
|
||||||
customerInfoExtractor?: CustomerInfoExtractor // Callback to extract customer info from relationship
|
|
||||||
disabled?: boolean
|
|
||||||
providers?: {
|
|
||||||
mollie?: MollieConfig
|
|
||||||
stripe?: StripeConfig
|
|
||||||
test?: TestProviderConfig
|
|
||||||
}
|
|
||||||
webhooks?: {
|
|
||||||
basePath?: string
|
|
||||||
cors?: boolean
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collection types
|
|
||||||
export interface PaymentRecord {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
customer?: string
|
|
||||||
description?: string
|
|
||||||
id: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
provider: string
|
|
||||||
providerData?: Record<string, unknown>
|
|
||||||
providerId: string
|
|
||||||
status: PaymentStatus
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomerRecord {
|
|
||||||
address?: {
|
|
||||||
city?: string
|
|
||||||
country?: string
|
|
||||||
line1?: string
|
|
||||||
line2?: string
|
|
||||||
postalCode?: string
|
|
||||||
state?: string
|
|
||||||
}
|
|
||||||
createdAt: string
|
|
||||||
email?: string
|
|
||||||
id: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
name?: string
|
|
||||||
phone?: string
|
|
||||||
providerIds?: Record<string, string>
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InvoiceRecord {
|
|
||||||
amount: number
|
|
||||||
billingAddress?: {
|
|
||||||
city: string
|
|
||||||
country: string
|
|
||||||
line1: string
|
|
||||||
line2?: string
|
|
||||||
postalCode: string
|
|
||||||
state?: string
|
|
||||||
}
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
customer?: string // Optional relationship to customer collection
|
|
||||||
customerInfo?: {
|
|
||||||
company?: string
|
|
||||||
email: string
|
|
||||||
name: string
|
|
||||||
phone?: string
|
|
||||||
taxId?: string
|
|
||||||
}
|
|
||||||
dueDate?: string
|
|
||||||
id: string
|
|
||||||
items: InvoiceItem[]
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
number: string
|
|
||||||
paidAt?: string
|
|
||||||
status: InvoiceStatus
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InvoiceItem {
|
|
||||||
description: string
|
|
||||||
quantity: number
|
|
||||||
totalAmount: number
|
|
||||||
unitAmount: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InvoiceStatus =
|
|
||||||
| 'draft'
|
|
||||||
| 'open'
|
|
||||||
| 'paid'
|
|
||||||
| 'uncollectible'
|
|
||||||
| 'void'
|
|
||||||
|
|
||||||
// Plugin type
|
|
||||||
export interface BillingPluginOptions extends BillingPluginConfig {
|
|
||||||
disabled?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error types
|
|
||||||
export class BillingError extends Error {
|
|
||||||
constructor(
|
|
||||||
message: string,
|
|
||||||
public code: string,
|
|
||||||
public provider?: string,
|
|
||||||
public details?: Record<string, unknown>
|
|
||||||
) {
|
|
||||||
super(message)
|
|
||||||
this.name = 'BillingError'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PaymentProviderError extends BillingError {
|
|
||||||
constructor(
|
|
||||||
message: string,
|
|
||||||
provider: string,
|
|
||||||
code?: string,
|
|
||||||
details?: Record<string, unknown>
|
|
||||||
) {
|
|
||||||
super(message, code || 'PROVIDER_ERROR', provider, details)
|
|
||||||
this.name = 'PaymentProviderError'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebhookError extends BillingError {
|
|
||||||
constructor(
|
|
||||||
message: string,
|
|
||||||
provider: string,
|
|
||||||
code?: string,
|
|
||||||
details?: Record<string, unknown>
|
|
||||||
) {
|
|
||||||
super(message, code || 'WEBHOOK_ERROR', provider, details)
|
|
||||||
this.name = 'WebhookError'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
/**
|
|
||||||
* PayloadCMS type definitions for hooks and handlers
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { PayloadRequest, User } from 'payload'
|
|
||||||
|
|
||||||
// Collection hook types
|
|
||||||
export interface CollectionBeforeChangeHook<T = Record<string, unknown>> {
|
|
||||||
data: T
|
|
||||||
operation: 'create' | 'delete' | 'update'
|
|
||||||
originalDoc?: T
|
|
||||||
req: PayloadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CollectionAfterChangeHook<T = Record<string, unknown>> {
|
|
||||||
doc: T
|
|
||||||
operation: 'create' | 'delete' | 'update'
|
|
||||||
previousDoc?: T
|
|
||||||
req: PayloadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CollectionBeforeValidateHook<T = Record<string, unknown>> {
|
|
||||||
data?: T
|
|
||||||
operation: 'create' | 'update'
|
|
||||||
originalDoc?: T
|
|
||||||
req: PayloadRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access control types
|
|
||||||
export interface AccessArgs<T = unknown> {
|
|
||||||
data?: T
|
|
||||||
id?: number | string
|
|
||||||
req: {
|
|
||||||
payload: unknown
|
|
||||||
user: null | User
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoice item type for hooks
|
|
||||||
export interface InvoiceItemData {
|
|
||||||
description: string
|
|
||||||
quantity: number
|
|
||||||
totalAmount?: number
|
|
||||||
unitAmount: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoice data type for hooks
|
|
||||||
export interface InvoiceData {
|
|
||||||
amount?: number
|
|
||||||
billingAddress?: {
|
|
||||||
city?: string
|
|
||||||
country?: string
|
|
||||||
line1?: string
|
|
||||||
line2?: string
|
|
||||||
postalCode?: string
|
|
||||||
state?: string
|
|
||||||
}
|
|
||||||
currency?: string
|
|
||||||
customer?: string // Optional relationship
|
|
||||||
customerInfo?: {
|
|
||||||
company?: string
|
|
||||||
email?: string
|
|
||||||
name?: string
|
|
||||||
phone?: string
|
|
||||||
taxId?: string
|
|
||||||
}
|
|
||||||
dueDate?: string
|
|
||||||
items?: InvoiceItemData[]
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
notes?: string
|
|
||||||
number?: string
|
|
||||||
paidAt?: string
|
|
||||||
payment?: string
|
|
||||||
status?: string
|
|
||||||
subtotal?: number
|
|
||||||
taxAmount?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payment data type for hooks
|
|
||||||
export interface PaymentData {
|
|
||||||
amount?: number
|
|
||||||
currency?: string
|
|
||||||
customer?: string
|
|
||||||
description?: string
|
|
||||||
invoice?: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
provider?: string
|
|
||||||
providerData?: Record<string, unknown>
|
|
||||||
providerId?: string | number
|
|
||||||
status?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Customer data type for hooks
|
|
||||||
export interface CustomerData {
|
|
||||||
address?: {
|
|
||||||
city?: string
|
|
||||||
country?: string
|
|
||||||
line1?: string
|
|
||||||
line2?: string
|
|
||||||
postalCode?: string
|
|
||||||
state?: string
|
|
||||||
}
|
|
||||||
email?: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
name?: string
|
|
||||||
phone?: string
|
|
||||||
providerIds?: Record<string, string | number>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refund data type for hooks
|
|
||||||
export interface RefundData {
|
|
||||||
amount?: number
|
|
||||||
currency?: string
|
|
||||||
description?: string
|
|
||||||
metadata?: Record<string, unknown>
|
|
||||||
payment?: { id: string | number } | string
|
|
||||||
providerData?: Record<string, unknown>
|
|
||||||
providerId?: string | number
|
|
||||||
reason?: string
|
|
||||||
status?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Document types with required fields after creation
|
|
||||||
export interface PaymentDocument extends PaymentData {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
id: string | number
|
|
||||||
provider: string
|
|
||||||
providerId: string | number
|
|
||||||
status: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomerDocument extends CustomerData {
|
|
||||||
createdAt: string
|
|
||||||
id: string | number
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InvoiceDocument extends InvoiceData {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
customer?: string // Optional relationship
|
|
||||||
customerInfo?: { // Optional when customer relationship exists
|
|
||||||
company?: string
|
|
||||||
email: string
|
|
||||||
name: string
|
|
||||||
phone?: string
|
|
||||||
taxId?: string
|
|
||||||
}
|
|
||||||
billingAddress?: { // Optional when customer relationship exists
|
|
||||||
city: string
|
|
||||||
country: string
|
|
||||||
line1: string
|
|
||||||
line2?: string
|
|
||||||
postalCode: string
|
|
||||||
state?: string
|
|
||||||
}
|
|
||||||
id: string | number
|
|
||||||
items: InvoiceItemData[]
|
|
||||||
number: string
|
|
||||||
status: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RefundDocument extends RefundData {
|
|
||||||
amount: number
|
|
||||||
createdAt: string
|
|
||||||
currency: string
|
|
||||||
id: string | number
|
|
||||||
payment: { id: string } | string
|
|
||||||
providerId: string
|
|
||||||
refunds?: string[]
|
|
||||||
status: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user