@tpmjs/official-invoice-terms-extract 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2025 TPMJS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,52 @@
1
+ import * as ai from 'ai';
2
+
3
+ /**
4
+ * Invoice Terms Extract Tool for TPMJS
5
+ * Extracts payment terms, due dates, and late fees from invoice text
6
+ */
7
+ /**
8
+ * Input interface for invoice terms extraction
9
+ */
10
+ interface InvoiceTermsExtractInput {
11
+ invoiceText: string;
12
+ }
13
+ /**
14
+ * Late fee structure
15
+ */
16
+ interface LateFee {
17
+ type: 'percentage' | 'fixed' | 'daily' | 'monthly';
18
+ amount: number;
19
+ currency?: string;
20
+ description: string;
21
+ }
22
+ /**
23
+ * Discount terms for early payment
24
+ */
25
+ interface EarlyPaymentDiscount {
26
+ discountPercentage: number;
27
+ paymentDays: number;
28
+ description: string;
29
+ }
30
+ /**
31
+ * Output interface for extracted payment terms
32
+ */
33
+ interface PaymentTerms {
34
+ netDays: number | null;
35
+ dueDate: string | null;
36
+ invoiceDate: string | null;
37
+ invoiceNumber: string | null;
38
+ totalAmount: number | null;
39
+ currency: string | null;
40
+ lateFee: LateFee | null;
41
+ earlyPaymentDiscount: EarlyPaymentDiscount | null;
42
+ paymentMethods: string[];
43
+ additionalTerms: string[];
44
+ summary: string;
45
+ }
46
+ /**
47
+ * Invoice Terms Extract Tool
48
+ * Extracts payment terms, due dates, and late fees from invoice text
49
+ */
50
+ declare const invoiceTermsExtractTool: ai.Tool<InvoiceTermsExtractInput, PaymentTerms>;
51
+
52
+ export { type EarlyPaymentDiscount, type LateFee, type PaymentTerms, invoiceTermsExtractTool as default, invoiceTermsExtractTool };
package/dist/index.js ADDED
@@ -0,0 +1,268 @@
1
+ import { tool, jsonSchema } from 'ai';
2
+
3
+ // src/index.ts
4
+ function extractNetDays(text) {
5
+ const normalizedText = text.toLowerCase();
6
+ const netMatch = normalizedText.match(/net\s+(\d+)(?:\s+days?)?/i);
7
+ if (netMatch && netMatch[1]) {
8
+ return Number.parseInt(netMatch[1], 10);
9
+ }
10
+ const daysMatch = normalizedText.match(/(?:payment\s+)?(?:due\s+)?(?:in\s+)?(\d+)\s+days/i);
11
+ if (daysMatch && daysMatch[1]) {
12
+ return Number.parseInt(daysMatch[1], 10);
13
+ }
14
+ if (normalizedText.includes("due on receipt") || normalizedText.includes("payable immediately")) {
15
+ return 0;
16
+ }
17
+ if (normalizedText.includes("end of month") || normalizedText.includes("eom")) {
18
+ return 30;
19
+ }
20
+ return null;
21
+ }
22
+ function extractDueDate(text) {
23
+ const datePatterns = [
24
+ /due(?:\s+date)?:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i,
25
+ /payment\s+due:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i,
26
+ /due\s+by:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i,
27
+ /due\s+on:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i
28
+ ];
29
+ for (const pattern of datePatterns) {
30
+ const match = text.match(pattern);
31
+ if (match && match[1]) {
32
+ return match[1];
33
+ }
34
+ }
35
+ const writtenDateMatch = text.match(
36
+ /due\s+(?:date|on|by)?:?\s*(\w+\s+\d{1,2},?\s+\d{4}|\d{1,2}\s+\w+\s+\d{4})/i
37
+ );
38
+ if (writtenDateMatch && writtenDateMatch[1]) {
39
+ return writtenDateMatch[1];
40
+ }
41
+ return null;
42
+ }
43
+ function extractInvoiceDate(text) {
44
+ const datePatterns = [
45
+ /invoice\s+date:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i,
46
+ /date:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i,
47
+ /dated:?\s*(\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})/i
48
+ ];
49
+ for (const pattern of datePatterns) {
50
+ const match = text.match(pattern);
51
+ if (match && match[1]) {
52
+ return match[1];
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ function extractInvoiceNumber(text) {
58
+ const patterns = [
59
+ /invoice\s+(?:number|#|no\.?):?\s*([A-Z0-9\-]+)/i,
60
+ /invoice:?\s+([A-Z0-9\-]+)/i,
61
+ /#\s*([A-Z0-9\-]+)/
62
+ ];
63
+ for (const pattern of patterns) {
64
+ const match = text.match(pattern);
65
+ if (match && match[1]) {
66
+ return match[1];
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ function extractTotalAmount(text) {
72
+ const patterns = [
73
+ /(?:total|amount\s+due|balance\s+due):?\s*\$?\s*([\d,]+\.?\d*)/i,
74
+ /\$\s*([\d,]+\.?\d*)/,
75
+ /(?:total|amount\s+due|balance\s+due):?\s*([A-Z]{3})\s*([\d,]+\.?\d*)/i
76
+ ];
77
+ for (const pattern of patterns) {
78
+ const match = text.match(pattern);
79
+ if (match) {
80
+ const hasCurrencyCode = match[0].match(/[A-Z]{3}/);
81
+ const currency = hasCurrencyCode && match[1] ? match[1] : "USD";
82
+ const amountStr = hasCurrencyCode && match[2] ? match[2] : match[1];
83
+ if (amountStr) {
84
+ const amount = Number.parseFloat(amountStr.replace(/,/g, ""));
85
+ if (!isNaN(amount)) {
86
+ return { amount, currency };
87
+ }
88
+ }
89
+ }
90
+ }
91
+ return { amount: null, currency: null };
92
+ }
93
+ function extractLateFee(text) {
94
+ const normalizedText = text.toLowerCase();
95
+ const percentageMatch = normalizedText.match(
96
+ /([\d.]+)%\s*(?:per\s+month|monthly|late\s+fee|interest)/i
97
+ );
98
+ if (percentageMatch && percentageMatch[1]) {
99
+ return {
100
+ type: "monthly",
101
+ amount: Number.parseFloat(percentageMatch[1]),
102
+ description: `${percentageMatch[1]}% per month late fee`
103
+ };
104
+ }
105
+ const dailyMatch = normalizedText.match(/([\d.]+)%\s*(?:per\s+day|daily)/i);
106
+ if (dailyMatch && dailyMatch[1]) {
107
+ return {
108
+ type: "daily",
109
+ amount: Number.parseFloat(dailyMatch[1]),
110
+ description: `${dailyMatch[1]}% per day late fee`
111
+ };
112
+ }
113
+ const fixedMatch = text.match(/(?:late\s+fee|fee)(?:\s+of)?\s*\$?\s*([\d.]+)/i);
114
+ if (fixedMatch && fixedMatch[1]) {
115
+ return {
116
+ type: "fixed",
117
+ amount: Number.parseFloat(fixedMatch[1]),
118
+ currency: "USD",
119
+ description: `$${fixedMatch[1]} late fee`
120
+ };
121
+ }
122
+ return null;
123
+ }
124
+ function extractEarlyPaymentDiscount(text) {
125
+ const discountMatch = text.match(/(\d+)\/(\d+)\s+(?:net|n)\s+\d+/i);
126
+ if (discountMatch && discountMatch[1] && discountMatch[2]) {
127
+ return {
128
+ discountPercentage: Number.parseInt(discountMatch[1], 10),
129
+ paymentDays: Number.parseInt(discountMatch[2], 10),
130
+ description: `${discountMatch[1]}% discount if paid within ${discountMatch[2]} days`
131
+ };
132
+ }
133
+ const explicitMatch = text.match(/(\d+)%\s+discount\s+(?:if\s+paid\s+)?within\s+(\d+)\s+days/i);
134
+ if (explicitMatch && explicitMatch[1] && explicitMatch[2]) {
135
+ return {
136
+ discountPercentage: Number.parseInt(explicitMatch[1], 10),
137
+ paymentDays: Number.parseInt(explicitMatch[2], 10),
138
+ description: `${explicitMatch[1]}% discount if paid within ${explicitMatch[2]} days`
139
+ };
140
+ }
141
+ return null;
142
+ }
143
+ function extractPaymentMethods(text) {
144
+ const normalizedText = text.toLowerCase();
145
+ const methods = [];
146
+ const paymentPatterns = [
147
+ { keyword: "check", value: "Check" },
148
+ { keyword: "wire transfer", value: "Wire Transfer" },
149
+ { keyword: "ach", value: "ACH" },
150
+ { keyword: "credit card", value: "Credit Card" },
151
+ { keyword: "debit card", value: "Debit Card" },
152
+ { keyword: "paypal", value: "PayPal" },
153
+ { keyword: "venmo", value: "Venmo" },
154
+ { keyword: "cash", value: "Cash" },
155
+ { keyword: "bank transfer", value: "Bank Transfer" },
156
+ { keyword: "online payment", value: "Online Payment" }
157
+ ];
158
+ paymentPatterns.forEach(({ keyword, value }) => {
159
+ if (normalizedText.includes(keyword)) {
160
+ methods.push(value);
161
+ }
162
+ });
163
+ return [...new Set(methods)];
164
+ }
165
+ function extractAdditionalTerms(text) {
166
+ const terms = [];
167
+ const normalizedText = text.toLowerCase();
168
+ const termPatterns = [
169
+ { keyword: "non-refundable", term: "Payment is non-refundable" },
170
+ { keyword: "prepayment required", term: "Prepayment required" },
171
+ { keyword: "partial payments", term: "Partial payments accepted" },
172
+ { keyword: "installment", term: "Installment payments available" },
173
+ {
174
+ keyword: "collection costs",
175
+ term: "Customer responsible for collection costs"
176
+ },
177
+ {
178
+ keyword: "interest charges",
179
+ term: "Interest charges apply to overdue amounts"
180
+ }
181
+ ];
182
+ termPatterns.forEach(({ keyword, term }) => {
183
+ if (normalizedText.includes(keyword)) {
184
+ terms.push(term);
185
+ }
186
+ });
187
+ return terms;
188
+ }
189
+ function extractPaymentTerms(invoiceText) {
190
+ if (!invoiceText || invoiceText.trim().length === 0) {
191
+ throw new Error("Invoice text cannot be empty");
192
+ }
193
+ const netDays = extractNetDays(invoiceText);
194
+ const dueDate = extractDueDate(invoiceText);
195
+ const invoiceDate = extractInvoiceDate(invoiceText);
196
+ const invoiceNumber = extractInvoiceNumber(invoiceText);
197
+ const { amount, currency } = extractTotalAmount(invoiceText);
198
+ const lateFee = extractLateFee(invoiceText);
199
+ const earlyPaymentDiscount = extractEarlyPaymentDiscount(invoiceText);
200
+ const paymentMethods = extractPaymentMethods(invoiceText);
201
+ const additionalTerms = extractAdditionalTerms(invoiceText);
202
+ let summary = "Extracted payment terms: ";
203
+ const summaryParts = [];
204
+ if (netDays !== null) {
205
+ summaryParts.push(`Net ${netDays} days`);
206
+ }
207
+ if (dueDate) {
208
+ summaryParts.push(`due ${dueDate}`);
209
+ }
210
+ if (amount !== null) {
211
+ summaryParts.push(`total ${currency || "USD"} ${amount.toFixed(2)}`);
212
+ }
213
+ if (lateFee) {
214
+ summaryParts.push(`late fee: ${lateFee.description}`);
215
+ }
216
+ if (earlyPaymentDiscount) {
217
+ summaryParts.push(`discount: ${earlyPaymentDiscount.description}`);
218
+ }
219
+ if (paymentMethods.length > 0) {
220
+ summaryParts.push(`accepted: ${paymentMethods.join(", ")}`);
221
+ }
222
+ summary += summaryParts.length > 0 ? summaryParts.join("; ") : "No specific payment terms identified";
223
+ return {
224
+ netDays,
225
+ dueDate,
226
+ invoiceDate,
227
+ invoiceNumber,
228
+ totalAmount: amount,
229
+ currency,
230
+ lateFee,
231
+ earlyPaymentDiscount,
232
+ paymentMethods,
233
+ additionalTerms,
234
+ summary
235
+ };
236
+ }
237
+ var invoiceTermsExtractTool = tool({
238
+ description: "Extracts and normalizes payment terms from invoice text or payment terms sections. Identifies net payment days (e.g., Net 30), due dates, invoice dates, invoice numbers, total amounts, currencies, late fee structures (percentage, fixed, daily, monthly), early payment discounts, accepted payment methods, and additional terms. Returns structured payment terms ready for processing or calendar entry.",
239
+ inputSchema: jsonSchema({
240
+ type: "object",
241
+ properties: {
242
+ invoiceText: {
243
+ type: "string",
244
+ description: "The invoice text or payment terms section to analyze"
245
+ }
246
+ },
247
+ required: ["invoiceText"],
248
+ additionalProperties: false
249
+ }),
250
+ execute: async ({ invoiceText }) => {
251
+ if (typeof invoiceText !== "string") {
252
+ throw new Error("Invoice text must be a string");
253
+ }
254
+ if (invoiceText.trim().length === 0) {
255
+ throw new Error("Invoice text cannot be empty");
256
+ }
257
+ try {
258
+ return extractPaymentTerms(invoiceText);
259
+ } catch (error) {
260
+ throw new Error(
261
+ `Failed to extract invoice terms: ${error instanceof Error ? error.message : String(error)}`
262
+ );
263
+ }
264
+ }
265
+ });
266
+ var index_default = invoiceTermsExtractTool;
267
+
268
+ export { index_default as default, invoiceTermsExtractTool };
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@tpmjs/official-invoice-terms-extract",
3
+ "version": "0.1.0",
4
+ "description": "Extracts payment terms, due dates, and late fees from invoice text",
5
+ "type": "module",
6
+ "keywords": [
7
+ "tpmjs",
8
+ "legal",
9
+ "invoice",
10
+ "payment",
11
+ "terms"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "devDependencies": {
23
+ "tsup": "^8.3.5",
24
+ "typescript": "^5.9.3",
25
+ "@tpmjs/tsconfig": "0.0.0"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/anthropics/tpmjs.git",
33
+ "directory": "packages/tools/official/invoice-terms-extract"
34
+ },
35
+ "homepage": "https://tpmjs.com",
36
+ "license": "MIT",
37
+ "tpmjs": {
38
+ "category": "legal",
39
+ "frameworks": [
40
+ "vercel-ai"
41
+ ],
42
+ "tools": [
43
+ {
44
+ "name": "invoiceTermsExtractTool",
45
+ "description": "Extracts payment terms, due dates, and late fees from invoice text",
46
+ "parameters": [
47
+ {
48
+ "name": "invoiceText",
49
+ "type": "string",
50
+ "description": "Invoice text or terms section",
51
+ "required": true
52
+ }
53
+ ],
54
+ "returns": {
55
+ "type": "PaymentTerms",
56
+ "description": "Extracted and normalized payment terms"
57
+ }
58
+ }
59
+ ]
60
+ },
61
+ "dependencies": {
62
+ "ai": "6.0.0-beta.124"
63
+ },
64
+ "scripts": {
65
+ "build": "tsup",
66
+ "dev": "tsup --watch",
67
+ "type-check": "tsc --noEmit",
68
+ "clean": "rm -rf dist .turbo"
69
+ }
70
+ }