Skip to content
bitzorcas
中EN

Concept

Industry Extensions calculator libraries

A source- and official-authority-verified overview of the Finance, HR, and Auction pure-calculation assemblies, their absence from the runtime host, hard-coded policy, rounding and date boundaries, and the policy-version governance required for commercial GA.

Last updated

Industry Extensions consists of three optional .NET libraries: Finance, HR, and Auction. They expose side-effect-free static calculations and stable Errors. They are not business modules integrated into the API host: there are no endpoints, DI registrations, permissions, features, persistence, tenant context, centralized configuration, or automated tests.

1. Three assemblies

AssemblyPublic capabilityDependency
FinanceBrackets, income tax, mortgage, private-loan detail, penaltyDomain
HRAnnual/marriage/maternity/paternity/bereavement/medical leave and policy scheduleDomain
AuctionDefault/custom bracket commission and fixed-rate commissionDomain + Finance

Finance is also referenced by LegalCalculators for TaxBracket and the bracket engine. It is therefore not consumed only through an explicitly selected industry profile; it is already a compile-time transitive dependency of LegalCalculators.

2. Runtime boundary

no ProjectReference /endpoints

Consumer assembly

Finance
pure static calculators

HR
pure static calculators

Auction
commission

Domain
Result · Error · ValueObject

LegalCalculators
reuses TaxBracket

API host

All three projects are in the solution, but the API host does not reference them. A governance marker is hosted in BitzOrcas.Platform.Application, so the Registry can report an IndustryExtensions module identity even when the calculator assemblies are not loaded. Operations must distinguish catalog presence from callable capability.

3. Public calculators

CalculatorCurrent scenarios
BracketTaxCalculatorQuick formula and progressive brackets
IncomeTaxCalculatorComprehensive income, labor-service withholding, annual bonus
MortgageCalculatorEqual-installment/equal-principal amounts, interest, schedules
LoanDetailCalculatorFour-times-LPR checks, period/segment interest, allocation, compound ceiling
PenaltyCalculatorAgreed/daily/LPR reference and a 130% adjustment suggestion
LeaveCalculatorAnnual/prorated/marriage/maternity/paternity/bereavement/medical leave
AuctionCommissionCalculatorDefault/custom brackets and a fixed rate

These are type-level APIs, not CQRS use cases. Earlier instructions to inspect request contracts, handlers, post-commit events, cache, and audit did not match this implementation.

4. Minimal Finance use

Estimate annual comprehensive-income tax
// The caller first proves tax year, residence, jurisdiction, and policy version.
var taxableIncome = annualIncome
- basicDeduction
- socialInsuranceDeduction
- specialAdditionalDeduction;
// The current decimal-only API stores none of that evidence and returns no bracket lines.
var tax = IncomeTaxCalculator.CalcIndividualIncomeTax(taxableIncome);
// Error has a stable code; success is rounded to two places AwayFromZero.
if (tax.IsFailure)
return tax.Error;
return tax.Value;

The seven comprehensive-income brackets match the current official table, but the API has no TaxYear. The separate-tax method for an annual bonus relies on a policy currently extended through 2027-12-31; the hard-coded method will not expire automatically.

5. Minimal HR use

Calculate maternity leave with an explicit regional policy
// A preset is only a reference snapshot; production should load an approved version.
var policy = LeavePolicies.Guangdong;
// The current engine always adds 15 days for difficult labor.
var days = LeaveCalculator.CalcMaternityDays(
schedule: policy,
isDifficultLabor: true,
multipleBirthCount: 1);
// Persist policy version and source with the result, never the final number alone.
if (days.IsFailure)
return days.Error;
return days.Value;

Official local rules can use a different difficult-labor increment, which the current schedule cannot express. Preset EffectiveFrom also defaults to the process date rather than the legal effective date.

6. Minimal Auction use

Calculate commission from an explicit contract rate
// The owner first establishes contract terms, auction type, and paying party.
var result = AuctionCommissionCalculator.CalcCommissionByRate(
hammerPrice: 2_500_000m,
commissionRate: 0.03m);
// The current API rejects every rate above 5% without distinguishing legal scenarios.
if (result.IsFailure)
return result.Error;
// The decimal does not say seller/buyer, tax treatment, contract, or bracket evidence.
return result.Value;

Article 56 of the Auction Law first permits an agreed commission. Its no-agreement rule and Article 57’s specific category use a 5% ceiling. A single universal cap is broader than that legal structure.

7. Official-authority check

These links demonstrate the need for versioned policy. Runtime code must not scrape a webpage and activate text without review.

8. Deterministic is not reproducible

Most methods are pure for identical numeric inputs. The same business fact is not reproducible because inputs omit PolicyId/Version, TaxYear, ContractDate, Jurisdiction, DayCountConvention, and RoundingPolicy. LeavePolicies also takes DateTime.Today, producing different value objects on different startup dates.

A commercial result needs normalized facts, rule version and hash, source reference, effective interval, calculation time, rounding contract, line-by-line breakdown, and actor/approval evidence.

9. Numeric and date boundaries

Amounts use decimal and most final results round two places AwayFromZero. BracketTaxCalculator itself does not round, while schedules round each period. Total-interest APIs and schedule sums can therefore differ by cents.

InterestSegment documentation calls both endpoints inclusive; code subtracts dates and excludes EndDate. Segments are not validated for order, overlap, or gaps, and reverse or same-day segments are silently skipped.

10. Validation gaps

The bracket engine does not validate ascending limits, final coverage, rates, quick deductions, or duplicates. LeavePolicy validates strict ordering and nonnegative top-level leave days, but not nonnegative tier years/days. Mortgage has no upper bound for years * 12, decimal exponentiation, or schedule size.

Error descriptions are hard-coded Chinese. Several helpers return bare decimal rather than Result, including a ratio that accepts negative values.

11. Chapter map

12. Commercial-GA red lines

  1. Bind every result to Jurisdiction, PolicyId/Version, EffectiveFrom/To, and SourceHash;
  2. select legal and regional rules from an approved policy store, not implicit static defaults;
  3. return a breakdown, input snapshot, rounding rule, and date convention;
  4. correct the broad Auction 5% cap, mechanical Penalty 130% suggestion, and month-based leave proration;
  5. resolve InterestSegment inclusivity and validate order, overlap, and gaps;
  6. add strict input and capacity limits for brackets, mortgage, and leave policy;
  7. put authorization, tenant, privacy, audit, idempotency, and use restrictions in an application wrapper;
  8. operate an ingest-review-approve-publish-supersede regulatory workflow;
  9. require golden, property, boundary, independent-reference, and expert-signoff evidence;
  10. eliminate the current zero-test condition before any production consumption.

13. Source navigation

Terminal window
# Public calculators, records, and error catalogs.
rg -n "^public (static |sealed )?(class|record)|public static (Result|decimal|int)" \
src/Platform/IndustryExtensions -g '*.cs'
# Prove host absence and the Finance consumers.
rg -n "IndustryExtensions" src/Hosts src/Platform -g '*.csproj' -g '*.cs'
# Policy evidence, endpoints, and tests should currently have no complete implementation.
rg -n "PolicyVersion|SourceHash|EffectiveTo|GenerateEndpoint|\[Fact\]" \
src/Platform/IndustryExtensions tests -g '*.cs'

Module catalog · Legal Calculators · I18n

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%