Skip to main content

BIR Form 1601-C — Monthly Remittance Return of Income Taxes Withheld on Compensation

How MotorPH generates the monthly 1601-C, where every figure comes from, and what each of the form's 40 entry points contains. The layout reproduced is the January 2018 (ENCS) revision — the authoritative blank form sits next to this file (1601C final Jan 2018 with DPA.pdf).

1. Overview

BIR Form 1601-C is the return every employer (withholding agent) files monthly to remit the income tax withheld from employee compensation. MotorPH generates a format-only reproduction of the form pre-filled with the month's payroll aggregates — it is a working paper for the person who files, not an eFPS/eBIRForms submission. Actual filing and payment happen through eFPS or eBIRForms, due on or before the 10th day of the month following the month of withholding (some eFPS filer groups have later staggered dates).

  • UI: Payroll → Government Forms (/government-forms) → BIR 1601-C card → Generate. The dialog defaults to the previous calendar month and lets you pick any month within the last five years, then download BIR-1601C-YYYY-MM.pdf.
  • ATC: WW010 (withholding tax on compensation, private employer).
  • Related annual forms: BIR 1604-C Alphalist and BIR 2316 cover the same withholding annually — and they, not the monthly 1601-C, apply the ₱90,000 13th-month exemption cap (see §6).

2. Architecture and data flow

payslips (per payroll run) bonuses (paid outside payroll runs)
│ │
▼ ▼
PayslipRepository.findMonthlyFiguresForAllEmployees(year, month)
per-employee SUMs across every run in the BonusRepository
calendar month: grossIncome, totalBenefits, .findMonthlyBonusTotal(year, month)
SSS/PHIC/HDMF employee shares, withholdingTax │
│ │
└──────────────┬──────────────────────────────┘

GovernmentFormsServiceImpl.getBir1601c(year, month) ← lines 14–25 computed here

Bir1601cDto ── GET /api/government-forms/bir-1601c?year&month

Bir1601cDialog.tsx (period pickers, uncapped-bonus warning, empty state)

Bir1601cTemplate.tsx ← lines 26–36 derived here; renders two [data-pdf-page] divs

renderPagedNodeToPdfBlob (html2canvas + jsPDF) → BIR-1601C-YYYY-MM.pdf

Key source files:

ConcernFile
Line 14–25 computationbackend/src/main/java/com/motorph/payroll/service/impl/GovernmentFormsServiceImpl.java (getBir1601c)
DTO (field ↔ line comments)backend/src/main/java/com/motorph/payroll/dto/Bir1601cDto.java
Monthly payslip aggregatebackend/src/main/java/com/motorph/payroll/repository/PayslipRepository.java (findMonthlyFiguresForAllEmployees)
Monthly bonus totalbackend/src/main/java/com/motorph/payroll/repository/BonusRepository.java (findMonthlyBonusTotal)
REST endpoint + RBACbackend/src/main/java/com/motorph/payroll/controller/GovernmentFormsController.java (GET /api/government-forms/bir-1601c)
Dialog (period, warning, download)frontend/src/components/government-forms/Bir1601cDialog.tsx
Form template + lines 26–36frontend/src/components/government-forms/Bir1601cTemplate.tsx
HTML → PDF rendererfrontend/src/components/payroll/payslipPdf.tsx (renderPagedNodeToPdfBlob)

The upstream payslip columns are produced by PayrollServiceImpl during payroll run generation: grossIncome includes regular/OT pay, allowances folded into gross, and night shift differential; totalBenefits is the de minimis bundle (rice + phone + clothing allowances) and is excluded from the withholding tax base; withholdingTax comes from the TRAIN monthly bracket table (withholding_tax_brackets). Bonuses never pass through payroll runs — they are recorded in the bonuses table and enter this form only through the monthly bonus total.

3. Complete entry-point map (1–40)

Column meanings — Where: backend = computed in getBir1601c; frontend = derived or hard-coded in Bir1601cTemplate.tsx; profile = taken from the Company Profile (CompanyProfileDto, editable via the Employer Profile drawer on the Government Forms page); blank = left empty for manual completion at filing time.

Part I — Background Information (entries 1–13)

#Form labelWhereSource / value
1For the Month of (MM/YYYY)frontendSelected period from the dialog, rendered as a 2+4 comb box
2Amended Return?frontendAlways No (amended returns not supported)
3Any Taxes Withheld?frontendYes iff line 25 (totalTaxWithheld) > 0, else No
4No. of Sheets AttachedblankNot tracked
5ATCfrontendHard-coded WW010
6Taxpayer Identification Number (TIN)profiletin (digits only, 3-3-3 comb) + branch code (defaults 0000)
7RDO CodeprofilerdoCode (digits only)
8Withholding Agent's NameprofileregisteredName
9Registered AddressprofileregisteredAddress
9AZIP CodeprofilezipCode (digits only)
10Contact NumberprofilephoneNumber (digits only, 4-3-4 comb)
11Category of Withholding AgentprofilePrivate / Government checkbox from withholdingAgentCategory
12Email AddressblankRenders empty even when the profile has one — known gap, see §6
13 / 13APayees availing of tax relief under Special Law / Tax Treaty?frontendNeither box checked; 13A blank (treaty relief not modeled)

Part II — Computation of Tax (entries 14–36)

Lines 14–25 are computed server-side; each is summed at full precision and only then rounded to 2 decimals, HALF_UP. Lines 26–36 are derived client-side purely to keep the printed numbering contiguous — every input to them is zero in this system.

#Form labelWhereFormula / source
14Total Amount of CompensationbackendΣ payslip grossIncome + Σ payslip totalBenefits + monthly bonus total — everything actually paid in the month
15Statutory Minimum Wage for MWEsbackendAlways 0 — MWE status is not tracked
16Holiday Pay, OT, Night Shift Differential, Hazard Pay (MWEs only)frontendAlways 0 — MWE status not tracked (non-MWE OT/NSD is already inside line 14's gross)
1713th Month Pay and Other BenefitsbackendfindMonthlyBonusTotal(year, month) — the full bonus paid in the month, deliberately not capped at ₱90,000 (§6a)
18De Minimis BenefitsbackendΣ payslip totalBenefits (rice + phone + clothing allowances)
19SSS, GSIS, PHIC, HDMF Mandatory Contributions & Union Dues (employee share)backendΣ (SSS + PhilHealth + Pag-IBIG employee shares); no GSIS/union dues in this system
20Other Non-Taxable Compensation (specify)backendAlways 0 — not tracked
21Total Non-Taxable Compensation (Sum of Items 15 to 20)backend17 + 18 + 19 (15, 16, 20 are always 0)
22Total Taxable Compensation (Item 14 Less Item 21)backend14 − 21
23Less: Taxable compensation not subject to withholding (≤ ₱250,000/year, non-MWE)frontendAlways 0 — annualized-income exemption not modeled
24Net Taxable Compensation (Item 22 Less Item 23)backendEquals line 22 (since 23 = 0)
25Total Taxes WithheldbackendΣ payslip withholdingTax (TRAIN monthly brackets)
26Add/(Less): Adjustment of Taxes Withheld from Previous Month/s (From Part IV Schedule 1, Item 4)frontendAlways 0 — no prior-month adjustment tracking
27Taxes Withheld for Remittance (Sum of Items 25 and 26)frontend25 + 26 = line 25
28Less: Tax Remitted in Return Previously Filed (if amended)frontendAlways 0 — amended returns not supported
29Other Remittances Made (specify)frontendAlways 0
30Total Tax Remittances Made (Sum of Items 28 and 29)frontend0
31Tax Still Due/(Over-remittance) (Item 27 Less Item 30)frontend= line 27 = line 25
32Add: Penalties — SurchargefrontendAlways 0 — penalties not tracked
33InterestfrontendAlways 0
34CompromisefrontendAlways 0
35Total Penalties (Sum of Items 32 to 34)frontend0
36TOTAL AMOUNT STILL DUE/(Over-remittance) (Sum of Items 31 and 35)frontend= line 31 = line 25. In practice 36 == 27 == 31 == 25

Part III — Details of Payment (entries 37–40)

All four rows (Drawee Bank/Agency, Number, Date, Amount) render blank — payment details only exist at filing/payment time and are completed manually.

#Particulars
37Cash/Bank Debit Memo
38Check
39Tax Debit Memo
40Others (specify below)

Part IV — Schedule 1 (Adjustment of Taxes Withheld from Previous Months)

Rendered blank (three empty adjustment rows plus the "Should be Tax Due / Adjustments" grid). The schedule's Total Adjustment feeds Part II line 26 and is therefore always 0.00. Page 2 also carries the perjury/Data-Privacy-Act declaration and signature blocks (blank) and a footer note listing every line this system reports as zero.

4. Computation walkthrough (worked example)

One employee in June 2026, plus one bonus paid that month (this is the exact fixture in GovernmentFormsServiceImplBir1601cTest.getBir1601c_singleEmployee_computesLines14Through25FromPayslipAggregates):

Input (month aggregate)Amount
Gross income (payslips)42,500.50
De minimis benefits (rice/phone/clothing)1,500.00
SSS employee share1,687.50
PhilHealth employee share1,093.75
Pag-IBIG employee share200.00
Withholding tax4,321.99
Bonus paid in the month10,000.00
LineComputationResult
1442,500.50 + 1,500.00 + 10,000.0054,000.50
17bonus10,000.00
18de minimis1,500.00
191,687.50 + 1,093.75 + 200.002,981.25
2110,000.00 + 1,500.00 + 2,981.2514,481.25
22 = 2454,000.50 − 14,481.2539,519.25
25 = 27 = 31 = 36withholding tax4,321.99

Rounding: the service sums raw payslip values at full precision and applies setScale(2, RoundingMode.HALF_UP) per output line at the very end. Subtraction happens before rounding — e.g. raw inputs 10,000.010 − 100.009 produce line 22 = 9,900.00 (raw 9,900.001), which is also consistent with the displayed 10,000.01 − 100.01. Null aggregates (an empty month makes the bonus SUM return null) are treated as zero.

5. Behavior at the edges

  • Empty month (no payslips, no bonuses): every line is 0.00, employee count 0; the dialog shows "No payroll data found for {Month} {Year}" and disables the download.
  • Bonus-only month (bonuses paid, but no payroll run): the form still renders — line 14 = 17 = 21 = the bonus total and line 22 = 0. This is why the dialog's hasData check is employeeCount > 0 || totalCompensation > 0, not the count alone.
  • Item 3 flips to "No" when nothing was withheld — a 1601-C must still be filed for months with no withholding.
  • Amounts print into BIR-style comb boxes (one bordered cell per digit, 7 whole digits
    • 2 cents). Anything beyond 9,999,999.99 would not fit the printed cells.

6. Known limitations and deliberate tradeoffs

  1. Line 17 is uncapped (deliberate). The full monthly bonus is reported non-taxable. The ₱90,000 annual 13th-month/other-benefits exemption cap requires each employee's year-to-date bonus total, which a single-month aggregate view does not have. The annual forms — 1604-C Alphalist (ReportingServiceImpl.getBirAlphalist, which splits the YTD bonus at ₱90,000 into non-taxable/taxable-excess) and 2316 — do apply the cap and are authoritative. For an employee who crosses ₱90,000 during the year, this month's 1601-C and the year-end forms will legitimately disagree. The dialog shows a permanent warning about this, and the tradeoff is documented in a long comment inside getBir1601c and asserted by GovernmentFormsServiceImplTest.
  2. MWE status is not tracked → lines 15 and 16 are always zero. If the company employs statutory minimum wage earners, their exempt pay is not broken out.
  3. No adjustment/amended/penalty tracking → lines 20, 23, 26, 28–29, 32–34 (and hence 27, 30–31, 35–36 beyond echoing line 25), Part III (37–40), and Part IV Schedule 1 are always zero or blank. Anyone filing an amended return or paying late must fill these in by hand.
  4. Entry 12 (email) renders blank even when the company profile has an email address.
  5. RBAC asymmetry: the backend endpoint accepts hr.employees.view or payroll.manage (GovernmentFormsController), but the frontend route guard requires hr.employees.manage or payroll.manage (frontend/src/App.tsx, /government-forms route). A view-only HR user can call the API directly but cannot reach the page.
  6. Format-only output. The generated PDF recreates the form layout in HTML (the official PDF has no fillable AcroForm fields); the page-1/page-2 break differs slightly from the officially typeset form, and the legal-boilerplate guidelines page is omitted. Filing still goes through eFPS/eBIRForms.

7. Testing

TestWhat it coversRun
backend/src/test/java/com/motorph/payroll/service/impl/GovernmentFormsServiceImplBir1601cTest.javaPart II line arithmetic (14–25): empty/null month, single- and multi-employee aggregation, null-field resilience, HALF_UP rounding order, bonus-only month, no-bonus month, always-zero lines 15/20 and the 24 == 22 invariantcd backend && mvn test -Dtest=GovernmentFormsServiceImplBir1601cTest
backend/src/test/java/com/motorph/payroll/service/impl/GovernmentFormsServiceImplTest.javaThe uncapped line-17 policy, contrasted with 2316/alphalist which apply the ₱90k capcd backend && mvn test -Dtest=GovernmentFormsServiceImplTest
e2e/HR_Recruitment/bir-1601c-form.spec.tsDialog defaults (previous month), uncapped-bonus warning, all Part I–IV sections and line labels rendering, both PDF pages, PDF download filename, period-change refetchnpx playwright test e2e/HR_Recruitment/bir-1601c-form.spec.ts --project=chromium
e2e/HR_Recruitment/government-forms.spec.tsGovernment Forms launchpad wiring (card → dialog opens)npx playwright test e2e/HR_Recruitment/government-forms.spec.ts

E2E prerequisites: the docker stack must be running on http://localhost:5173, and the seeded demo data provides payroll runs for the previous calendar month — which is exactly the dialog's default period. Amounts in the template render as per-character comb boxes, so e2e asserts labels and structure, never amount text.