ejosterberg/opensalestax
Composer 安装命令:
composer require ejosterberg/opensalestax
包简介
PHP SDK for the OpenSalesTax engine — open-source US sales tax calculation API.
关键字:
README 文档
README
PHP SDK for the OpenSalesTax engine — the open-source, self-hostable US sales tax calculation API.
Status: v0.1 alpha. API surface stable. Tested against engine v0.14 — v0.24.
Why this exists
US sales tax is a mess: ~10,000 jurisdictions, ~50,000 ZIPs, rates change quarterly, taxability rules vary per state per category. The commercial APIs (Avalara, TaxJar, Stripe Tax) charge $0.50–$10+ per transaction or 0.5% of revenue.
OpenSalesTax is the open-source self-hostable engine. This SDK is the PHP wrapper around its v1 HTTP API — composer require, point at your engine, get tax.
$client = new OpenSalesTax\Client(baseUrl: 'http://your-engine:8080'); $result = $client->calculate( address: new Address(zip5: '55401'), lineItems: [new LineItem(amount: '100.00', category: 'general')], ); echo $result->taxTotal; // "8.025"
That's it. ~200 LOC of stateless wrapper code — no business logic, no caching, no surprise dependencies. The complexity lives in the engine; this SDK just calls it.
Install
composer require ejosterberg/opensalestax
Requires PHP 8.2+ (uses class-level readonly syntax for DTOs) and a reachable OpenSalesTax engine (self-host via the engine's docker-compose).
Quickstart
use OpenSalesTax\Client; use OpenSalesTax\Address; use OpenSalesTax\LineItem; $client = new Client(baseUrl: 'http://localhost:8080'); $result = $client->calculate( address: new Address(zip5: '55401'), lineItems: [ new LineItem(amount: '100.00', category: 'general'), new LineItem(amount: '50.00', category: 'clothing'), ], ); echo $result->subtotal; // "150.00" echo $result->taxTotal; // "8.025" foreach ($result->lines as $line) { echo "{$line->category}: \${$line->tax}\n"; if ($line->note !== null) { echo " → {$line->note}\n"; // e.g. "Clothing is non-taxable in Minnesota..." } }
API surface
$client = new Client( baseUrl: 'http://your-engine:8080', apiKey: 'optional-x-api-key', // null if engine doesn't require auth timeoutSeconds: 10.0, httpClient: null, // optional PSR-18 override (Guzzle 7 default) ); $client->health(); // HealthResponse{status, version, databaseConnected} $client->states(); // StatesResponse{states[StateInfo], total} $client->rates(zip5: '55401'); // RatesResponse{input, jurisdictions[], combinedRatePct, disclaimer} $client->calculate($address, $lineItems); // CalculateResponse{subtotal, taxTotal, lines[], disclaimer}
Each line in a CalculateResponse carries the per-jurisdiction breakdown:
foreach ($result->lines as $line) { foreach ($line->jurisdictions as $j) { echo " {$j->type:9} {$j->name:50} {$j->ratePct}% \${$j->tax}\n"; // state Minnesota 6.875% $6.8750 // county Hennepin County 0.15% $0.1500 // city Minneapolis 0.5% $0.5000 // district Hennepin County Transit Sales Tax 0.5% $0.5000 } }
Sums reconcile exactly: $line->tax === sum($line->jurisdictions[*]->tax). Use the breakdown for accounting (state/county/city splits); use $line->tax for the customer-facing total.
Tax categories
Standard categories the engine recognizes: general (default), clothing, groceries, prescription_drugs, prepared_food, digital_goods. Per-state taxability rules apply (e.g. clothing is non-taxable in Minnesota; groceries in most states).
Amounts are decimal strings
Amounts are strings, not integers (cents) or floats. Strings preserve the engine's exact precision; the engine quantizes per-jurisdiction in fixed-point. Convert from cents in your own code if you need to:
$cents = 9999; $amount = number_format($cents / 100, 2, '.', ''); // "99.99" new LineItem(amount: $amount, category: 'general');
Errors
Flat hierarchy. All errors extend OpenSalesTax\Exceptions\OpenSalesTaxException:
OpenSalesTaxApiException— non-2xx HTTP from the engine; carriesstatusCode,rawBody,errorBody.OpenSalesTaxNetworkException— transport failure (timeout, DNS); wraps the underlying PSR-18 exception viagetPrevious().OpenSalesTaxValidationException— client-side input rejected before sending (bad ZIP regex, negative amount).
try { $result = $client->calculate(...); } catch (OpenSalesTaxApiException $e) { error_log("Engine returned {$e->statusCode}: {$e->rawBody}"); } catch (OpenSalesTaxNetworkException $e) { error_log("Cannot reach engine: " . $e->getMessage()); }
Quality bar
- PHPStan level=max — zero suppressed errors
- PHP-CS-Fixer with PSR-12 + risky rules — zero violations
- PHPUnit — 21 unit + integration tests, 54 assertions, all passing
- GitHub Actions CI matrix on PHP 8.2 / 8.3 / 8.4
- DCO sign-off required on every commit
Engine compatibility
This SDK targets the OpenSalesTax v1 HTTP API. Tested against engine v0.14 — v0.24. The v1 API surface has been stable across that range. Pin both in production:
ejosterberg/opensalestax: ^0.1
opensalestax engine: v0.20+ (recommended; older versions had a state-bleed bug fixed in v0.22)
What this SDK is NOT
- Not the engine. See open-sales-tax for the calculator itself.
- Not Stripe-aware. For a Stripe Tax replacement, layer opensalestax-stripe-php on top.
- Not a tax-filing service — calculation only. The merchant remits.
- Not a caching layer. Caching is the consumer's job because cache-invalidation policy is platform-specific.
Disclaimer
Tax calculations are provided as-is for convenience. The merchant is solely responsible for tax-collection accuracy and remittance to the appropriate jurisdictions. Verify against your state Department of Revenue before remitting.
Contributing
DCO sign-off (git commit -s) required on every commit. See CONTRIBUTING.md. Apache 2.0 + SPDX header on every source file.
License
ejosterberg/opensalestax 适用场景与选型建议
ejosterberg/opensalestax 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 399 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 05 月 05 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「api」 「sdk」 「tax」 「sales-tax」 「opensalestax」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 ejosterberg/opensalestax 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 ejosterberg/opensalestax 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 ejosterberg/opensalestax 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
API client for validating Tax Identification Number.
Validate the format of EU vat numbers.
Module allowing creation of tax rates and categories in the CMS via SiteConfig
A PSR-7 compatible library for making CRUD API endpoints
Australian Tax Rules for OroCommerce
Custom Post Type UI Plugin for Wordpress found at https://wordpress.org/plugins/custom-post-type-ui/
统计信息
- 总下载量: 399
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 44
- 依赖项目数: 11
- 推荐数: 0
其他信息
- 授权协议: Apache-2.0
- 更新时间: 2026-05-05