payrolla-mcp 0.2.4 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +7 -3
  2. package/dist/index.js +167 -47
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -55,15 +55,19 @@ Calculate payroll for a single employee.
55
55
  - `month` - Starting month (1-12)
56
56
  - `periodCount` - Number of months (optional, default: 1)
57
57
  - `ssiType` - SSI type: 'S4A', 'S4B', or 'S4C' (optional, default: 'S4A')
58
- - `extraPayments` - Array of extra payments (optional)
58
+ - `extraPayments` - Array of extra payments (optional, supports `paymentType` = RegularPayment/Overtime/SocialAid/ExtraPay)
59
59
  - `customParams` - Custom global parameters (optional)
60
+ - `cumulativeIncomeTaxBase` - Starting income tax base to carry over
61
+ - `cumulativeMinWageIncomeTaxBase` - Starting minimum wage income tax base to carry over
62
+ - `transferredSSIBase1` - Starting transferred SSI base 1
63
+ - `transferredSSIBase2` - Starting transferred SSI base 2
60
64
 
61
65
  ### calculate_bulk_payroll
62
66
 
63
67
  Calculate payroll for multiple employees with shared parameters.
64
68
 
65
69
  **Input:**
66
- - `employees` - Array of employee objects
70
+ - `employees` - Array of employee objects (each can include extra payments with `paymentType` and starting cumulative/transfer bases)
67
71
  - `year` - Calculation year
68
72
  - `month` - Starting month
69
73
  - `periodCount` - Number of months (use 12 for yearly)
@@ -120,4 +124,4 @@ Plan yearly payroll considering potential changes.
120
124
 
121
125
  ```
122
126
  User: I have 3 employees: Ali 35k net, Ayse 45k net, Mehmet 60k gross.
123
- What's my yearly budget if I give 10% raise and minimum wage becomes 30k?
127
+ What's my yearly budget if I give 10% raise and minimum wage becomes 30k?
package/dist/index.js CHANGED
@@ -30,6 +30,23 @@ function mapSSIType(ssiType) {
30
30
  function mapCalculationType(calcType) {
31
31
  return calcType === "Gross" ? CalculationType.Gross : CalculationType.Net;
32
32
  }
33
+ function mapPaymentType(paymentType) {
34
+ switch (paymentType) {
35
+ case 1:
36
+ case "RegularPayment":
37
+ return PaymentType.RegularPayment;
38
+ case 2:
39
+ case "Overtime":
40
+ return PaymentType.Overtime;
41
+ case 3:
42
+ case "SocialAid":
43
+ return PaymentType.SocialAid;
44
+ case 4:
45
+ case "ExtraPay":
46
+ default:
47
+ return PaymentType.ExtraPay;
48
+ }
49
+ }
33
50
  function buildCustomGlobalParams(customParams) {
34
51
  if (!customParams) return void 0;
35
52
  return {
@@ -50,7 +67,11 @@ async function calculatePayroll(client, input) {
50
67
  month,
51
68
  periodCount = 1,
52
69
  extraPayments,
53
- customParams
70
+ customParams,
71
+ cumulativeIncomeTaxBase = 0,
72
+ cumulativeMinWageIncomeTaxBase = 0,
73
+ transferredSSIBase1 = 0,
74
+ transferredSSIBase2 = 0
54
75
  } = input;
55
76
  const payments = [
56
77
  {
@@ -66,21 +87,17 @@ async function calculatePayroll(client, input) {
66
87
  payments.push({
67
88
  paymentAmount: extra.amount,
68
89
  paymentName: extra.name,
69
- paymentType: PaymentType.ExtraPay,
90
+ paymentType: mapPaymentType(extra.paymentType),
70
91
  paymentRef: `extra_${i + 2}`,
71
92
  calculationType: extra.type === "Net" ? CalculationType.Net : CalculationType.Gross
72
93
  });
73
94
  }
74
95
  }
75
- const model = {
76
- calcDate: `${year}-${String(month).padStart(2, "0")}-01`,
96
+ const baseModel = {
77
97
  wageAmount: wage,
78
- cumulativeIncomeTaxBase: 0,
79
- cumulativeMinWageIncomeTaxBase: 0,
80
98
  ssiType: mapSSIType(ssiType),
81
99
  wageCalculationType: mapCalculationType(calculationType),
82
100
  wagePeriodType: PaymentPeriodType.Monthly,
83
- periodCount,
84
101
  periodLengthType: PeriodLengthType.Month,
85
102
  payments,
86
103
  calculationParams: {
@@ -88,16 +105,40 @@ async function calculatePayroll(client, input) {
88
105
  customGlobalParams: buildCustomGlobalParams(customParams)
89
106
  }
90
107
  };
91
- const result = await client.calculate(model);
92
108
  let totalCost = 0;
93
109
  let totalNet = 0;
94
110
  let totalGross = 0;
95
111
  const periods = [];
96
- for (const payroll of result.payrolls) {
112
+ let incomeTaxBase = cumulativeIncomeTaxBase;
113
+ let minWageIncomeTaxBase = cumulativeMinWageIncomeTaxBase;
114
+ let transferredBase1 = transferredSSIBase1;
115
+ let transferredBase2 = transferredSSIBase2;
116
+ for (let i = 0; i < periodCount; i++) {
117
+ const calcDate = new Date(year, month - 1 + i, 1);
118
+ const calcYear = calcDate.getFullYear();
119
+ const calcMonth = calcDate.getMonth() + 1;
120
+ const model = {
121
+ ...baseModel,
122
+ calcDate: `${calcYear}-${String(calcMonth).padStart(2, "0")}-01`,
123
+ cumulativeIncomeTaxBase: incomeTaxBase,
124
+ cumulativeMinWageIncomeTaxBase: minWageIncomeTaxBase,
125
+ transferredSSIBase1: transferredBase1,
126
+ transferredSSIBase2: transferredBase2,
127
+ periodCount: 1
128
+ };
129
+ const result = await client.calculate(model);
130
+ const payroll = result.payrolls?.[0];
131
+ if (!payroll) {
132
+ throw new Error("Payrolla calculation returned no payroll data");
133
+ }
97
134
  const pr = payroll.payrollResult;
98
135
  totalCost += payroll.totalCost;
99
136
  totalNet += pr.totalNet;
100
137
  totalGross += pr.totalGross;
138
+ const nextIncomeTaxBase = incomeTaxBase + pr.totalIncomeTaxBase;
139
+ const nextMinWageIncomeTaxBase = pr.totalMinWageIncomeTaxExemptionBase;
140
+ const nextTransferredBase1 = pr.transferredSSIBase1 ?? transferredBase1;
141
+ const nextTransferredBase2 = pr.transferredSSIBase2 ?? transferredBase2;
101
142
  periods.push({
102
143
  year: payroll.year,
103
144
  month: payroll.month,
@@ -107,8 +148,16 @@ async function calculatePayroll(client, input) {
107
148
  incomeTax: pr.totalIncomeTax,
108
149
  stampTax: pr.totalStampTax,
109
150
  employeeSSI: pr.totalSSIWorkerPrem,
110
- employerSSI: pr.totalSSIEmployerPrem
151
+ employerSSI: pr.totalSSIEmployerPrem,
152
+ cumulativeIncomeTaxBase: nextIncomeTaxBase,
153
+ cumulativeMinWageIncomeTaxBase: nextMinWageIncomeTaxBase,
154
+ transferredSSIBase1: nextTransferredBase1,
155
+ transferredSSIBase2: nextTransferredBase2
111
156
  });
157
+ incomeTaxBase = nextIncomeTaxBase;
158
+ minWageIncomeTaxBase = nextMinWageIncomeTaxBase;
159
+ transferredBase1 = nextTransferredBase1;
160
+ transferredBase2 = nextTransferredBase2;
112
161
  }
113
162
  return {
114
163
  employee: name,
@@ -134,7 +183,11 @@ async function calculateBulkPayroll(client, input) {
134
183
  month,
135
184
  periodCount,
136
185
  extraPayments: emp.extraPayments,
137
- customParams
186
+ customParams,
187
+ cumulativeIncomeTaxBase: emp.cumulativeIncomeTaxBase,
188
+ cumulativeMinWageIncomeTaxBase: emp.cumulativeMinWageIncomeTaxBase,
189
+ transferredSSIBase1: emp.transferredSSIBase1,
190
+ transferredSSIBase2: emp.transferredSSIBase2
138
191
  });
139
192
  employeeResults.push({
140
193
  name: result.employee,
@@ -228,34 +281,68 @@ async function simulateBudget(client, input) {
228
281
  const { employees, year, periodCount, scenario } = input;
229
282
  const defaults = getDefaultParams({ year });
230
283
  const customParams = applyScenario(defaults, scenario);
231
- const adjustedEmployees = employees.map((emp) => ({
232
- name: emp.name,
233
- wage: applyRaise(emp.wage, scenario.salaryRaisePercent),
234
- calculationType: emp.calculationType,
235
- originalWage: emp.wage
236
- }));
237
- const result = await calculateBulkPayroll(client, {
238
- employees: adjustedEmployees.map((emp) => ({
239
- name: emp.name,
240
- wage: emp.wage,
241
- calculationType: emp.calculationType
242
- })),
243
- year,
244
- month: 1,
245
- periodCount,
246
- customParams
247
- });
248
- const employeeResults = adjustedEmployees.map((emp, index) => {
249
- const empResult = result.employees[index];
250
- return {
284
+ const employeeResults = [];
285
+ let totalYearlyCost = 0;
286
+ let totalYearlyNet = 0;
287
+ let totalYearlyGross = 0;
288
+ for (const emp of employees) {
289
+ const adjustedWage = applyRaise(emp.wage, scenario.salaryRaisePercent);
290
+ let cumulativeIncomeTaxBase = 0;
291
+ let cumulativeMinWageIncomeTaxBase = 0;
292
+ let transferredSSIBase1 = 0;
293
+ let transferredSSIBase2 = 0;
294
+ let empTotalCost = 0;
295
+ let empTotalNet = 0;
296
+ let empTotalGross = 0;
297
+ for (let i = 0; i < periodCount; i++) {
298
+ const calcDate = new Date(year, i, 1);
299
+ const calcYear = calcDate.getFullYear();
300
+ const calcMonth = calcDate.getMonth() + 1;
301
+ const periodPayEvents = (emp.payEvents || []).filter(
302
+ (pe) => pe.year === calcYear && pe.month === calcMonth
303
+ );
304
+ const extraPayments = periodPayEvents.map((pe) => ({
305
+ name: pe.name,
306
+ amount: pe.amount,
307
+ type: pe.type,
308
+ paymentType: pe.paymentType
309
+ }));
310
+ const result = await calculatePayroll(client, {
311
+ name: emp.name,
312
+ wage: adjustedWage,
313
+ calculationType: emp.calculationType,
314
+ ssiType: emp.ssiType,
315
+ year: calcYear,
316
+ month: calcMonth,
317
+ periodCount: 1,
318
+ extraPayments: extraPayments.length > 0 ? extraPayments : void 0,
319
+ customParams,
320
+ cumulativeIncomeTaxBase,
321
+ cumulativeMinWageIncomeTaxBase,
322
+ transferredSSIBase1,
323
+ transferredSSIBase2
324
+ });
325
+ empTotalCost += result.totalCost;
326
+ empTotalNet += result.totalNet;
327
+ empTotalGross += result.totalGross;
328
+ const lastPeriod = result.periods[0];
329
+ cumulativeIncomeTaxBase = lastPeriod.cumulativeIncomeTaxBase;
330
+ cumulativeMinWageIncomeTaxBase = lastPeriod.cumulativeMinWageIncomeTaxBase;
331
+ transferredSSIBase1 = lastPeriod.transferredSSIBase1;
332
+ transferredSSIBase2 = lastPeriod.transferredSSIBase2;
333
+ }
334
+ employeeResults.push({
251
335
  name: emp.name,
252
- originalWage: emp.originalWage,
253
- adjustedWage: emp.wage,
254
- yearlyCost: empResult.totalCost,
255
- yearlyNet: empResult.totalNet,
256
- yearlyGross: empResult.totalGross
257
- };
258
- });
336
+ originalWage: emp.wage,
337
+ adjustedWage,
338
+ yearlyCost: empTotalCost,
339
+ yearlyNet: empTotalNet,
340
+ yearlyGross: empTotalGross
341
+ });
342
+ totalYearlyCost += empTotalCost;
343
+ totalYearlyNet += empTotalNet;
344
+ totalYearlyGross += empTotalGross;
345
+ }
259
346
  const effectiveTaxBrackets = customParams.incomeTaxLimits || defaults.incomeTaxBrackets.map((b) => ({
260
347
  limit: b.limit,
261
348
  rate: b.rate
@@ -267,10 +354,10 @@ async function simulateBudget(client, input) {
267
354
  effectiveTaxBrackets
268
355
  },
269
356
  summary: {
270
- totalYearlyCost: result.summary.totalYearlyCost,
271
- totalYearlyNet: result.summary.totalYearlyNet,
272
- totalYearlyGross: result.summary.totalYearlyGross,
273
- costPerEmployee: result.summary.totalYearlyCost / employees.length
357
+ totalYearlyCost,
358
+ totalYearlyNet,
359
+ totalYearlyGross,
360
+ costPerEmployee: totalYearlyCost / employees.length
274
361
  },
275
362
  employees: employeeResults
276
363
  };
@@ -492,7 +579,28 @@ function registerPrompts(server) {
492
579
  var ExtraPaymentSchema = z2.object({
493
580
  name: z2.string().describe("Name of the extra payment"),
494
581
  amount: z2.number().describe("Payment amount"),
495
- type: z2.enum(["Net", "Gross"]).describe("Payment type")
582
+ type: z2.enum(["Net", "Gross"]).describe("Payment type"),
583
+ paymentType: z2.union([
584
+ z2.literal(1),
585
+ z2.literal(2),
586
+ z2.literal(3),
587
+ z2.literal(4),
588
+ z2.enum(["RegularPayment", "Overtime", "SocialAid", "ExtraPay"])
589
+ ]).optional().describe("Payment type (1: RegularPayment, 2: Overtime, 3: SocialAid, 4: ExtraPay)")
590
+ });
591
+ var PayEventSchema = z2.object({
592
+ month: z2.number().min(1).max(12).describe("Month when the payment occurs (1-12)"),
593
+ year: z2.number().describe("Year when the payment occurs"),
594
+ name: z2.string().describe('Payment name (e.g., "Q2 Bonus")'),
595
+ amount: z2.number().describe("Payment amount"),
596
+ type: z2.enum(["Net", "Gross"]).describe("Whether the amount is net or gross"),
597
+ paymentType: z2.union([
598
+ z2.literal(1),
599
+ z2.literal(2),
600
+ z2.literal(3),
601
+ z2.literal(4),
602
+ z2.enum(["RegularPayment", "Overtime", "SocialAid", "ExtraPay"])
603
+ ]).optional().describe("Payment category: 1/RegularPayment, 2/Overtime, 3/SocialAid, 4/ExtraPay (default: 4)")
496
604
  });
497
605
  var CustomParamsSchema = z2.object({
498
606
  minWage: z2.number().optional().describe("Custom minimum wage (gross)"),
@@ -510,7 +618,11 @@ var EmployeeInputSchema = z2.object({
510
618
  wage: z2.number().describe("Wage amount"),
511
619
  calculationType: z2.enum(["Gross", "Net"]).describe("Whether wage is gross or net"),
512
620
  ssiType: z2.enum(["S4A", "S4B", "S4C"]).optional().describe("SSI type (default: S4A)"),
513
- extraPayments: z2.array(ExtraPaymentSchema).optional().describe("Extra payments like bonuses")
621
+ extraPayments: z2.array(ExtraPaymentSchema).optional().describe("Extra payments like bonuses"),
622
+ cumulativeIncomeTaxBase: z2.number().optional().describe("Starting cumulative income tax base"),
623
+ cumulativeMinWageIncomeTaxBase: z2.number().optional().describe("Starting cumulative minimum wage income tax base"),
624
+ transferredSSIBase1: z2.number().optional().describe("Starting transferred SSI base 1"),
625
+ transferredSSIBase2: z2.number().optional().describe("Starting transferred SSI base 2")
514
626
  });
515
627
  var ScenarioConfigSchema = z2.object({
516
628
  name: z2.string().optional().describe("Scenario name for comparison"),
@@ -556,7 +668,11 @@ function registerTools(server, client) {
556
668
  month: z2.number().min(1).max(12).describe("Starting month (1-12)"),
557
669
  periodCount: z2.number().min(1).max(12).optional().describe("Number of months to calculate (default: 1)"),
558
670
  extraPayments: z2.array(ExtraPaymentSchema).optional().describe("Extra payments like bonuses"),
559
- customParams: CustomParamsSchema.optional().describe("Custom global parameters to override defaults")
671
+ customParams: CustomParamsSchema.optional().describe("Custom global parameters to override defaults"),
672
+ cumulativeIncomeTaxBase: z2.number().optional().describe("Starting cumulative income tax base to carry from previous months"),
673
+ cumulativeMinWageIncomeTaxBase: z2.number().optional().describe("Starting cumulative minimum wage income tax base"),
674
+ transferredSSIBase1: z2.number().optional().describe("Starting transferred SSI base 1"),
675
+ transferredSSIBase2: z2.number().optional().describe("Starting transferred SSI base 2")
560
676
  },
561
677
  async (params) => {
562
678
  try {
@@ -623,7 +739,9 @@ function registerTools(server, client) {
623
739
  employees: z2.array(z2.object({
624
740
  name: z2.string().describe("Employee name"),
625
741
  wage: z2.number().describe("Current wage amount"),
626
- calculationType: z2.enum(["Gross", "Net"]).describe("Wage type")
742
+ calculationType: z2.enum(["Gross", "Net"]).describe("Wage type"),
743
+ ssiType: z2.enum(["S4A", "S4B", "S4C"]).optional().describe("SSI type (default: S4A)"),
744
+ payEvents: z2.array(PayEventSchema).optional().describe("Extra payments at specific months (e.g., bonuses)")
627
745
  })).describe("Array of employees"),
628
746
  year: z2.number().describe("Calculation year"),
629
747
  periodCount: z2.number().min(1).max(12).describe("Number of months (use 12 for yearly)"),
@@ -660,7 +778,9 @@ function registerTools(server, client) {
660
778
  employees: z2.array(z2.object({
661
779
  name: z2.string().describe("Employee name"),
662
780
  wage: z2.number().describe("Current wage"),
663
- calculationType: z2.enum(["Gross", "Net"]).describe("Wage type")
781
+ calculationType: z2.enum(["Gross", "Net"]).describe("Wage type"),
782
+ ssiType: z2.enum(["S4A", "S4B", "S4C"]).optional().describe("SSI type (default: S4A)"),
783
+ payEvents: z2.array(PayEventSchema).optional().describe("Extra payments at specific months (e.g., bonuses)")
664
784
  })).describe("Array of employees"),
665
785
  year: z2.number().describe("Calculation year"),
666
786
  periodCount: z2.number().min(1).max(12).describe("Number of months"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payrolla-mcp",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "MCP server for Payrolla payroll budget simulations - enables LLMs to calculate Turkish payroll and simulate budget scenarios",
5
5
  "author": "Payrolla",
6
6
  "license": "MIT",