tourze/freight-template-bundle
A Symfony bundle for managing freight and shipping templates, giving applications a structured way to define, store, and apply reusable freight rules. Integrates cleanly with Doctrine-backed projects to keep shipping template data organized and easy to maintain.
tourze/freight-template-bundle is a Symfony bundle (not a Laravel package) providing Doctrine-mapped entities for e-commerce freight/shipping templates — the "首件/续件" (first-unit / additional-unit) regional pricing model used by marketplace sellers.
Minimal steps:
composer require tourze/freight-template-bundle:0.0.1
Register it the Symfony way (Flex has no recipe at 0.0.x):
// config/bundles.php
Tourze\FreightTemplateBundle\FreightTemplateBundle::class => ['all' => true],
Then create the tables. The bundle ships entity mappings, not migrations you should edit — generate a migration into your app and treat it as yours from that point.
Where to look first:
src/Entity/ — the domain model. Expect a FreightTemplate (name, billing mode, free-shipping threshold) and one or more rule entities holding region + first/additional unit price pairs.src/Repository/ — what query surface you actually get. If it is bare ServiceEntityRepository, plan on writing your own finders.DependencyInjection/FreightTemplateExtension.php + src/Resources/config/services.yaml — the only configuration surface; read it before writing a service provider adapter.composer.json require — tells you whether the pricing math lives here or in a sibling tourze/freight-template core library. This is the single most important thing to check; the bundle may be persistence-only.First use case: persist one template with two region rules (e.g. "nationwide" default + "remote areas" surcharge), then load it back via the repository and assert you can reconstruct a quote. Do this before wiring any checkout code — if the entity graph cannot express your pricing model, you want to know on day one, not in integration.
Treat the bundle as the persistence layer, write the calculator yourself. Ship a small FreightQuoteService in your app:
final class FreightQuoteService
{
public function __construct(private FreightTemplateRepository $templates) {}
public function quote(int $templateId, string $regionCode, int $units, int $weightGrams): Money
{
$template = $this->templates->find($templateId);
$rule = $this->matchRule($template, $regionCode); // longest-prefix / most-specific wins
// first-unit price + ceil((units - first) / additional) * additional price
}
}
Keeping this outside the bundle means a 0.0.x upgrade can't silently change your totals.
Seed templates as data, not fixtures. Templates are business configuration edited by ops. Load them from a YAML/JSON file in a seeder or migration so staging and production converge, and so the same definitions are diffable in review.
Cache aggressively, invalidate on write. Templates change weekly at most but are read on every cart calculation. Wrap the repository in a decorator backed by your cache pool, keyed by template id, with invalidation on save.
Normalise region identifiers at the boundary. Whatever the rule entity stores (province names, adcodes, ISO codes), convert your address data into that exact form in one place — an address resolver — rather than in each caller. String-matching on "广东" vs "广东省" is the classic silent-failure bug in this domain.
Laravel integration: you almost certainly do not want the bundle. It declares a Symfony Bundle class, relies on AbstractBundle/Extension wiring and Doctrine's Symfony bridge, and has no Laravel service provider. Two viable routes: (a) composer require the underlying core library only and drive it from a Laravel service provider, or (b) require the bundle but skip bootstrap/providers.php — use the entities as plain Doctrine entities via laravel-doctrine/orm and bind repositories yourself. Verify composer why tourze/freight-template-bundle before committing to either.
"tourze/freight-template-bundle": "0.0.1"), not a caret constraint. There is no changelog detail beyond a commit link, so read every diff between releases yourself.ceil() versus per-shipment ceil() on weight, and from whether the first-unit price covers units 1..N or 0..N. Pin both behaviours with unit tests at the boundary (exactly one first-unit, exactly one additional unit).doctrine:schema:update touch these tables again.bin/console debug:container Tourze\\FreightTemplate confirms services registered; bin/console doctrine:mapping:info confirms entities are discovered. A bundle that "does nothing" is almost always a missing config/bundles.php entry or a Doctrine mapping not picked up.How can I help you explore Laravel packages today?