@hasna/microservices 0.0.4 → 0.0.6
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/bin/index.js +9 -1
- package/bin/mcp.js +9 -1
- package/dist/index.js +9 -1
- package/microservices/microservice-ads/src/cli/index.ts +198 -0
- package/microservices/microservice-ads/src/db/campaigns.ts +304 -0
- package/microservices/microservice-ads/src/mcp/index.ts +160 -0
- package/microservices/microservice-company/package.json +27 -0
- package/microservices/microservice-company/src/cli/index.ts +1126 -0
- package/microservices/microservice-company/src/db/company.ts +854 -0
- package/microservices/microservice-company/src/db/database.ts +93 -0
- package/microservices/microservice-company/src/db/migrations.ts +214 -0
- package/microservices/microservice-company/src/db/workflow-migrations.ts +44 -0
- package/microservices/microservice-company/src/index.ts +60 -0
- package/microservices/microservice-company/src/lib/audit.ts +168 -0
- package/microservices/microservice-company/src/lib/finance.ts +299 -0
- package/microservices/microservice-company/src/lib/settings.ts +85 -0
- package/microservices/microservice-company/src/lib/workflows.ts +698 -0
- package/microservices/microservice-company/src/mcp/index.ts +991 -0
- package/microservices/microservice-contracts/src/cli/index.ts +410 -23
- package/microservices/microservice-contracts/src/db/contracts.ts +430 -1
- package/microservices/microservice-contracts/src/db/migrations.ts +83 -0
- package/microservices/microservice-contracts/src/mcp/index.ts +312 -3
- package/microservices/microservice-domains/src/cli/index.ts +673 -0
- package/microservices/microservice-domains/src/db/domains.ts +613 -0
- package/microservices/microservice-domains/src/index.ts +21 -0
- package/microservices/microservice-domains/src/lib/brandsight.ts +285 -0
- package/microservices/microservice-domains/src/lib/godaddy.ts +328 -0
- package/microservices/microservice-domains/src/lib/namecheap.ts +474 -0
- package/microservices/microservice-domains/src/lib/registrar.ts +355 -0
- package/microservices/microservice-domains/src/mcp/index.ts +413 -0
- package/microservices/microservice-hiring/src/cli/index.ts +318 -8
- package/microservices/microservice-hiring/src/db/hiring.ts +503 -0
- package/microservices/microservice-hiring/src/db/migrations.ts +21 -0
- package/microservices/microservice-hiring/src/index.ts +29 -0
- package/microservices/microservice-hiring/src/lib/scoring.ts +206 -0
- package/microservices/microservice-hiring/src/mcp/index.ts +245 -0
- package/microservices/microservice-payments/src/cli/index.ts +255 -3
- package/microservices/microservice-payments/src/db/migrations.ts +18 -0
- package/microservices/microservice-payments/src/db/payments.ts +552 -0
- package/microservices/microservice-payments/src/mcp/index.ts +223 -0
- package/microservices/microservice-payroll/src/cli/index.ts +269 -0
- package/microservices/microservice-payroll/src/db/migrations.ts +26 -0
- package/microservices/microservice-payroll/src/db/payroll.ts +636 -0
- package/microservices/microservice-payroll/src/mcp/index.ts +246 -0
- package/microservices/microservice-shipping/src/cli/index.ts +211 -3
- package/microservices/microservice-shipping/src/db/migrations.ts +8 -0
- package/microservices/microservice-shipping/src/db/shipping.ts +453 -3
- package/microservices/microservice-shipping/src/mcp/index.ts +149 -1
- package/microservices/microservice-social/src/cli/index.ts +244 -2
- package/microservices/microservice-social/src/db/migrations.ts +33 -0
- package/microservices/microservice-social/src/db/social.ts +378 -4
- package/microservices/microservice-social/src/mcp/index.ts +221 -1
- package/microservices/microservice-subscriptions/src/cli/index.ts +315 -0
- package/microservices/microservice-subscriptions/src/db/migrations.ts +68 -0
- package/microservices/microservice-subscriptions/src/db/subscriptions.ts +567 -3
- package/microservices/microservice-subscriptions/src/mcp/index.ts +267 -1
- package/package.json +1 -1
|
@@ -14,6 +14,17 @@ import {
|
|
|
14
14
|
reconcileWithInvoice,
|
|
15
15
|
getPaymentStats,
|
|
16
16
|
getBalanceByProvider,
|
|
17
|
+
autoReconcile,
|
|
18
|
+
retryPayment,
|
|
19
|
+
listRetries,
|
|
20
|
+
getRetryStats,
|
|
21
|
+
convertCurrency,
|
|
22
|
+
feeAnalysis,
|
|
23
|
+
declineReport,
|
|
24
|
+
addDisputeEvidence,
|
|
25
|
+
splitPayment,
|
|
26
|
+
revenueForecast,
|
|
27
|
+
findReconciliationGaps,
|
|
17
28
|
type PaymentType,
|
|
18
29
|
type PaymentStatus,
|
|
19
30
|
type PaymentProvider,
|
|
@@ -154,6 +165,127 @@ paymentCmd
|
|
|
154
165
|
}
|
|
155
166
|
});
|
|
156
167
|
|
|
168
|
+
// --- Payment Retry ---
|
|
169
|
+
|
|
170
|
+
paymentCmd
|
|
171
|
+
.command("retry")
|
|
172
|
+
.description("Retry a failed payment")
|
|
173
|
+
.argument("<id>", "Payment ID to retry")
|
|
174
|
+
.option("--json", "Output as JSON", false)
|
|
175
|
+
.action((id, opts) => {
|
|
176
|
+
const attempt = retryPayment(id);
|
|
177
|
+
if (!attempt) {
|
|
178
|
+
console.error(`Cannot retry payment '${id}' — not found or not failed.`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (opts.json) {
|
|
183
|
+
console.log(JSON.stringify(attempt, null, 2));
|
|
184
|
+
} else {
|
|
185
|
+
console.log(`Retry attempt #${attempt.attempt} for payment ${id}: ${attempt.status}`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
paymentCmd
|
|
190
|
+
.command("retries")
|
|
191
|
+
.description("List retry attempts for a payment")
|
|
192
|
+
.argument("<paymentId>", "Payment ID")
|
|
193
|
+
.option("--json", "Output as JSON", false)
|
|
194
|
+
.action((paymentId, opts) => {
|
|
195
|
+
const retries = listRetries(paymentId);
|
|
196
|
+
|
|
197
|
+
if (opts.json) {
|
|
198
|
+
console.log(JSON.stringify(retries, null, 2));
|
|
199
|
+
} else {
|
|
200
|
+
if (retries.length === 0) {
|
|
201
|
+
console.log("No retry attempts found.");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
for (const r of retries) {
|
|
205
|
+
console.log(` Attempt #${r.attempt} [${r.status}] ${r.attempted_at || ""} ${r.error || ""}`);
|
|
206
|
+
}
|
|
207
|
+
console.log(`\n${retries.length} retry attempt(s)`);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// --- Payment Convert ---
|
|
212
|
+
|
|
213
|
+
paymentCmd
|
|
214
|
+
.command("convert")
|
|
215
|
+
.description("Convert currency amount")
|
|
216
|
+
.requiredOption("--from <currency>", "Source currency")
|
|
217
|
+
.requiredOption("--to <currency>", "Target currency")
|
|
218
|
+
.requiredOption("--amount <amount>", "Amount to convert")
|
|
219
|
+
.option("--json", "Output as JSON", false)
|
|
220
|
+
.action((opts) => {
|
|
221
|
+
const result = convertCurrency(parseFloat(opts.amount), opts.from, opts.to);
|
|
222
|
+
if (!result) {
|
|
223
|
+
console.error(`Unsupported currency pair: ${opts.from} -> ${opts.to}`);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (opts.json) {
|
|
228
|
+
console.log(JSON.stringify(result, null, 2));
|
|
229
|
+
} else {
|
|
230
|
+
console.log(`${result.original_amount} ${result.from} = ${result.converted_amount} ${result.to} (rate: ${result.rate})`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// --- Decline Report ---
|
|
235
|
+
|
|
236
|
+
paymentCmd
|
|
237
|
+
.command("decline-report")
|
|
238
|
+
.description("Show decline analytics for failed payments")
|
|
239
|
+
.option("--provider <provider>", "Filter by provider")
|
|
240
|
+
.option("--json", "Output as JSON", false)
|
|
241
|
+
.action((opts) => {
|
|
242
|
+
const report = declineReport(opts.provider as PaymentProvider | undefined);
|
|
243
|
+
|
|
244
|
+
if (opts.json) {
|
|
245
|
+
console.log(JSON.stringify(report, null, 2));
|
|
246
|
+
} else {
|
|
247
|
+
if (report.entries.length === 0) {
|
|
248
|
+
console.log("No declined payments found.");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
console.log("Decline Report:");
|
|
252
|
+
for (const e of report.entries) {
|
|
253
|
+
console.log(` [${e.provider}] "${e.description || "No description"}" — ${e.count} decline(s), $${e.total_amount.toFixed(2)}`);
|
|
254
|
+
}
|
|
255
|
+
console.log(`\nTotal: ${report.total_declined} decline(s), $${report.total_amount.toFixed(2)}`);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// --- Payment Split ---
|
|
260
|
+
|
|
261
|
+
paymentCmd
|
|
262
|
+
.command("split")
|
|
263
|
+
.description("Split a payment into marketplace commission splits")
|
|
264
|
+
.argument("<id>", "Payment ID")
|
|
265
|
+
.requiredOption("--splits <json>", "Split percentages as JSON (e.g. '{\"vendor1\":70,\"vendor2\":30}')")
|
|
266
|
+
.option("--json", "Output as JSON", false)
|
|
267
|
+
.action((id, opts) => {
|
|
268
|
+
let splits: Record<string, number>;
|
|
269
|
+
try {
|
|
270
|
+
splits = JSON.parse(opts.splits);
|
|
271
|
+
} catch {
|
|
272
|
+
console.error("Invalid JSON for --splits");
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const payment = splitPayment(id, splits);
|
|
277
|
+
if (!payment) {
|
|
278
|
+
console.error(`Payment '${id}' not found.`);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (opts.json) {
|
|
283
|
+
console.log(JSON.stringify(payment, null, 2));
|
|
284
|
+
} else {
|
|
285
|
+
console.log(`Payment ${id} split recorded: ${JSON.stringify(splits)}`);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
157
289
|
// --- Disputes ---
|
|
158
290
|
|
|
159
291
|
const disputeCmd = program
|
|
@@ -203,6 +335,27 @@ disputeCmd
|
|
|
203
335
|
}
|
|
204
336
|
});
|
|
205
337
|
|
|
338
|
+
disputeCmd
|
|
339
|
+
.command("add-evidence")
|
|
340
|
+
.description("Add evidence to a dispute")
|
|
341
|
+
.argument("<id>", "Dispute ID")
|
|
342
|
+
.requiredOption("--description <desc>", "Evidence description")
|
|
343
|
+
.option("--file-ref <path>", "File reference path")
|
|
344
|
+
.option("--json", "Output as JSON", false)
|
|
345
|
+
.action((id, opts) => {
|
|
346
|
+
const dispute = addDisputeEvidence(id, opts.description, opts.fileRef);
|
|
347
|
+
if (!dispute) {
|
|
348
|
+
console.error(`Dispute '${id}' not found.`);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (opts.json) {
|
|
353
|
+
console.log(JSON.stringify(dispute, null, 2));
|
|
354
|
+
} else {
|
|
355
|
+
console.log(`Evidence added to dispute ${id}: "${opts.description}"`);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
206
359
|
// --- Payouts ---
|
|
207
360
|
|
|
208
361
|
const payoutCmd = program
|
|
@@ -277,15 +430,18 @@ program
|
|
|
277
430
|
|
|
278
431
|
// --- Revenue ---
|
|
279
432
|
|
|
280
|
-
program
|
|
433
|
+
const revenueCmd = program
|
|
281
434
|
.command("revenue")
|
|
435
|
+
.description("Revenue reports and forecasting");
|
|
436
|
+
|
|
437
|
+
revenueCmd
|
|
438
|
+
.command("report")
|
|
282
439
|
.description("Revenue report for a period")
|
|
283
440
|
.requiredOption("--period <YYYY-MM>", "Month period (e.g. 2024-01)")
|
|
284
441
|
.option("--json", "Output as JSON", false)
|
|
285
442
|
.action((opts) => {
|
|
286
443
|
const [year, month] = opts.period.split("-").map(Number);
|
|
287
444
|
const startDate = `${year}-${String(month).padStart(2, "0")}-01`;
|
|
288
|
-
// Last day of month
|
|
289
445
|
const lastDay = new Date(year, month, 0).getDate();
|
|
290
446
|
const endDate = `${year}-${String(month).padStart(2, "0")}-${String(lastDay).padStart(2, "0")} 23:59:59`;
|
|
291
447
|
|
|
@@ -302,10 +458,38 @@ program
|
|
|
302
458
|
}
|
|
303
459
|
});
|
|
304
460
|
|
|
461
|
+
revenueCmd
|
|
462
|
+
.command("forecast")
|
|
463
|
+
.description("Project revenue for upcoming months based on recent trends")
|
|
464
|
+
.requiredOption("--months <n>", "Number of months to forecast")
|
|
465
|
+
.option("--json", "Output as JSON", false)
|
|
466
|
+
.action((opts) => {
|
|
467
|
+
const result = revenueForecast(parseInt(opts.months));
|
|
468
|
+
|
|
469
|
+
if (opts.json) {
|
|
470
|
+
console.log(JSON.stringify(result, null, 2));
|
|
471
|
+
} else {
|
|
472
|
+
console.log(`Revenue Forecast (${result.months_projected} months, trend: ${result.trend})`);
|
|
473
|
+
console.log(" Historical:");
|
|
474
|
+
for (const h of result.historical) {
|
|
475
|
+
console.log(` ${h.month}: $${h.revenue.toFixed(2)}`);
|
|
476
|
+
}
|
|
477
|
+
console.log(" Forecast:");
|
|
478
|
+
for (const f of result.forecast) {
|
|
479
|
+
console.log(` ${f.month}: $${f.projected_revenue.toFixed(2)} (projected)`);
|
|
480
|
+
}
|
|
481
|
+
console.log(` Average Monthly Revenue: $${result.average_monthly_revenue.toFixed(2)}`);
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
305
485
|
// --- Reconcile ---
|
|
306
486
|
|
|
307
|
-
program
|
|
487
|
+
const reconcileCmd = program
|
|
308
488
|
.command("reconcile")
|
|
489
|
+
.description("Reconciliation commands");
|
|
490
|
+
|
|
491
|
+
reconcileCmd
|
|
492
|
+
.command("link")
|
|
309
493
|
.description("Link a payment to an invoice")
|
|
310
494
|
.requiredOption("--payment <id>", "Payment ID")
|
|
311
495
|
.requiredOption("--invoice <id>", "Invoice ID")
|
|
@@ -324,6 +508,74 @@ program
|
|
|
324
508
|
}
|
|
325
509
|
});
|
|
326
510
|
|
|
511
|
+
reconcileCmd
|
|
512
|
+
.command("auto")
|
|
513
|
+
.description("Auto-reconcile payments to invoices by amount, email, and date")
|
|
514
|
+
.option("--from <date>", "Start date (YYYY-MM-DD)")
|
|
515
|
+
.option("--to <date>", "End date (YYYY-MM-DD)")
|
|
516
|
+
.option("--json", "Output as JSON", false)
|
|
517
|
+
.action((opts) => {
|
|
518
|
+
const result = autoReconcile(opts.from, opts.to);
|
|
519
|
+
|
|
520
|
+
if (opts.json) {
|
|
521
|
+
console.log(JSON.stringify(result, null, 2));
|
|
522
|
+
} else {
|
|
523
|
+
console.log("Auto-Reconciliation Results:");
|
|
524
|
+
console.log(` Matched: ${result.matched.length}`);
|
|
525
|
+
for (const m of result.matched) {
|
|
526
|
+
console.log(` Payment ${m.payment_id} -> Invoice ${m.invoice_id} (${m.confidence})`);
|
|
527
|
+
}
|
|
528
|
+
console.log(` Unmatched Payments: ${result.unmatched_payments.length}`);
|
|
529
|
+
console.log(` Unmatched Invoices: ${result.unmatched_invoices.length}`);
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
reconcileCmd
|
|
534
|
+
.command("check-gaps")
|
|
535
|
+
.description("Find reconciliation gaps — payments without invoices and vice versa")
|
|
536
|
+
.requiredOption("--from <date>", "Start date (YYYY-MM-DD)")
|
|
537
|
+
.requiredOption("--to <date>", "End date (YYYY-MM-DD)")
|
|
538
|
+
.option("--json", "Output as JSON", false)
|
|
539
|
+
.action((opts) => {
|
|
540
|
+
const gaps = findReconciliationGaps(opts.from, opts.to);
|
|
541
|
+
|
|
542
|
+
if (opts.json) {
|
|
543
|
+
console.log(JSON.stringify(gaps, null, 2));
|
|
544
|
+
} else {
|
|
545
|
+
console.log("Reconciliation Gaps:");
|
|
546
|
+
console.log(` Payments without invoice: ${gaps.payments_without_invoice.length}`);
|
|
547
|
+
for (const p of gaps.payments_without_invoice) {
|
|
548
|
+
console.log(` $${p.amount} ${p.currency} — ${p.customer_email || "no email"} (${p.id})`);
|
|
549
|
+
}
|
|
550
|
+
console.log(` Invoice IDs without succeeded payment: ${gaps.invoice_ids_without_payment.length}`);
|
|
551
|
+
for (const inv of gaps.invoice_ids_without_payment) {
|
|
552
|
+
console.log(` ${inv}`);
|
|
553
|
+
}
|
|
554
|
+
console.log(` Total gaps: ${gaps.gap_count}`);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// --- Fees ---
|
|
559
|
+
|
|
560
|
+
program
|
|
561
|
+
.command("fees")
|
|
562
|
+
.description("Fee analysis by provider for a given month")
|
|
563
|
+
.requiredOption("--month <YYYY-MM>", "Month period (e.g. 2026-03)")
|
|
564
|
+
.option("--json", "Output as JSON", false)
|
|
565
|
+
.action((opts) => {
|
|
566
|
+
const result = feeAnalysis(opts.month);
|
|
567
|
+
|
|
568
|
+
if (opts.json) {
|
|
569
|
+
console.log(JSON.stringify(result, null, 2));
|
|
570
|
+
} else {
|
|
571
|
+
console.log(`Fee Analysis: ${result.month}`);
|
|
572
|
+
for (const p of result.providers) {
|
|
573
|
+
console.log(` ${p.provider}: gross $${p.gross.toFixed(2)}, fees $${p.fees.toFixed(2)}, net $${p.net.toFixed(2)} (${p.transaction_count} txns)`);
|
|
574
|
+
}
|
|
575
|
+
console.log(` Total: gross $${result.total_gross.toFixed(2)}, fees $${result.total_fees.toFixed(2)}, net $${result.total_net.toFixed(2)}`);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
327
579
|
// --- Stats ---
|
|
328
580
|
|
|
329
581
|
program
|
|
@@ -60,4 +60,22 @@ export const MIGRATIONS: MigrationEntry[] = [
|
|
|
60
60
|
CREATE INDEX IF NOT EXISTS idx_payouts_status ON payouts(status);
|
|
61
61
|
`,
|
|
62
62
|
},
|
|
63
|
+
{
|
|
64
|
+
id: 2,
|
|
65
|
+
name: "retry_attempts",
|
|
66
|
+
sql: `
|
|
67
|
+
CREATE TABLE IF NOT EXISTS retry_attempts (
|
|
68
|
+
id TEXT PRIMARY KEY,
|
|
69
|
+
payment_id TEXT NOT NULL REFERENCES payments(id) ON DELETE CASCADE,
|
|
70
|
+
attempt INTEGER NOT NULL DEFAULT 1,
|
|
71
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'retrying', 'succeeded', 'failed')),
|
|
72
|
+
attempted_at TEXT,
|
|
73
|
+
error TEXT,
|
|
74
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_retry_attempts_payment_id ON retry_attempts(payment_id);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_retry_attempts_status ON retry_attempts(status);
|
|
79
|
+
`,
|
|
80
|
+
},
|
|
63
81
|
];
|