[{"data":1,"prerenderedAt":31},["ShallowReactive",2],{"$f3rfgcodz77kj7":3,"$fgph23vl6tmr9":23},{"content":4,"package":5,"version":22},"# Replacing the Estimator\n\nThe estimate is made by two services, and either can be replaced on its own.\n\n| Service ID                                                | Interface                            | Responsibility                                                        |\n|-----------------------------------------------------------|--------------------------------------|-----------------------------------------------------------------------|\n| `babdev_sylius_shipping_estimate.estimator.default`       | `ShippingEstimatorInterface`         | Works out what the cart costs to ship to an address                   |\n| `babdev_sylius_shipping_estimate.estimator`               | `ShippingEstimatorInterface`         | Dispatches `BeforeEstimateShippingEvent`, then delegates to the above |\n| `babdev_sylius_shipping_estimate.shop.estimate_responder` | `ShippingEstimateResponderInterface` | Turns the estimate into the JSON the widget reads                     |\n\nBoth interfaces are aliased to the service the plugin registers, so `decorates:` and autowiring work without naming the concrete classes.\n\n## Replacing How Rates Are Worked Out\n\n`BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimatorInterface` takes the cart and the address being estimated for, and answers with a `ShippingEstimate`:\n\n```php\n\u003C?php\n\nnamespace App\\Shipping;\n\nuse BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimate;\nuse BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimateOption;\nuse BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimateReasons;\nuse BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimatorInterface;\nuse Sylius\\Component\\Core\\Model\\AddressInterface;\nuse Sylius\\Component\\Core\\Model\\OrderInterface;\n\nfinal class CarrierApiShippingEstimator implements ShippingEstimatorInterface\n{\n    public function __construct(private CarrierApi $carrierApi)\n    {\n    }\n\n    public function estimate(OrderInterface $cart, AddressInterface $address): ShippingEstimate\n    {\n        $quotes = $this->carrierApi->quote($cart, $address);\n\n        if ($quotes->refusedForWeight()) {\n            return ShippingEstimate::unavailable('package_overweight');\n        }\n\n        if ($quotes->isEmpty()) {\n            return ShippingEstimate::unavailable(ShippingEstimateReasons::NOT_AVAILABLE);\n        }\n\n        return ShippingEstimate::of(...array_map(\n            static fn (Quote $quote): ShippingEstimateOption => new ShippingEstimateOption(\n                $quote->methodCode,\n                $quote->methodName,\n                $quote->amountInCents,\n                (string) $cart->getCurrencyCode(),\n            ),\n            $quotes->all(),\n        ));\n    }\n}\n```\n\nRegister it as the **inner** service, so listeners on `BeforeEstimateShippingEvent` still run:\n\n```yaml\nservices:\n    App\\Shipping\\CarrierApiShippingEstimator: ~\n\n    babdev_sylius_shipping_estimate.estimator.default:\n        alias: App\\Shipping\\CarrierApiShippingEstimator\n```\n\nReplacing `babdev_sylius_shipping_estimate.estimator` instead takes over the event dispatch as well, which means listeners stop being called. Prefer the inner service unless that is what you want.\n\n### Leave The Cart As You Found It\n\nSylius resolves shipping methods from the address on the shipment's order, so an estimate against the shop's own methods has to put the address being estimated for onto the cart. That address is a hypothetical the customer has not chosen, and leaving it behind hands whatever flushes the cart next an address they never asked for.\n\nAn implementation that puts anything on the cart or its shipments must put the original back, including when the estimate fails part way through. The plugin's own estimator does this in a `finally` block. The same applies to the shipment's shipping method if you swap it to price a row.\n\n### Amounts Are Integers\n\n`ShippingEstimateOption` carries the rate as an integer in the currency's minor units, which is what every shipping calculator reports and what a machine consumer needs. Formatting it for a person to read is the responder's job.\n\n## Reasons\n\nAn estimate with no options in it always carries a reason. The plugin's own are constants on `BabDev\\SyliusShippingEstimatePlugin\\Estimator\\ShippingEstimateReasons`:\n\n| Constant           | Value                         | Meaning                                                      |\n|--------------------|-------------------------------|--------------------------------------------------------------|\n| `NOT_AVAILABLE`    | `shipping_not_available`      | The estimate ran and found no rates                          |\n| `NOT_SUPPORTED`    | `shipping_not_supported`      | Shipping methods could not be resolved for the cart          |\n| `CALCULATOR_ERROR` | `shipping_calculator_error`   | Every shipping method errored out while being priced         |\n| `CANCELLED`        | `shipping_estimate_cancelled` | A listener stopped the estimate                              |\n\nYour estimator may report reasons of its own, including what your carriers actually refuse for, and nothing downstream assumes a reason came from that list. To word one for the customer, add a `data-message-{reason}` attribute to the widget's form; see [Customize the Output](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Fcustomize-the-output).\n\n## Adding To The Response\n\n`ShippingEstimate::withMetadata()` adds keys to the JSON payload without your having to replace the responder:\n\n```php\nreturn ShippingEstimate::of(...$options)->withMetadata('quoted_as_residential', true);\n```\n\n`ShippingEstimateOption` takes per-option metadata the same way, as its last constructor argument, which lands on that option's row.\n\nMetadata is merged **under** the keys the endpoint already sends, so `error`, `options`, `reason`, and `custom_reason` cannot be overwritten by it.\n\n## Replacing The Response\n\nReplace `BabDev\\SyliusShippingEstimatePlugin\\Http\\ShippingEstimateResponderInterface` to change the payload itself, or the status a reason is answered with.\n\nThe plugin's responder answers a canceled estimate with a `400` and a calculator error with a `500`; every other reason, including any of your own, gets a `200`, on the grounds that an estimate which ran and came back with nothing is an answer rather than a failure. That mapping is its second constructor argument:\n\n```yaml\nservices:\n    babdev_sylius_shipping_estimate.shop.estimate_responder:\n        class: BabDev\\SyliusShippingEstimatePlugin\\Http\\ShippingEstimateResponder\n        arguments:\n            - '@sylius.money_formatter'\n            - shipping_estimate_cancelled: 400\n              shipping_calculator_error: 500\n              package_overweight: 400\n```\n",{"name":6,"slug":7,"previousSlugs":8,"description":10,"github":11,"packagistName":14,"packageType":15,"hasDocumentation":16,"supported":16,"visible":16,"versions":17},"Sylius Shipping Estimate Plugin","shipping-estimate-plugin",[9],"syliusshippingestimateplugin","Adds a shipping estimator widget to a Sylius website's cart",{"owner":12,"repo":13},"BabDev","SyliusShippingEstimatePlugin","babdev\u002Fsylius-shipping-estimate-plugin","sylius-plugin",true,[18],{"version":19,"gitBranch":20,"released":21},"1.x","0.3",false,{"version":19,"gitBranch":20,"released":21},{"content":24,"package":25,"version":30},"- [Introduction](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Fintro)\n- [Installation & Setup](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Finstallation)\n- [Customize the Output](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Fcustomize-the-output)\n- [Hooking The Estimator](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Fhooking-the-estimator)\n- [Replacing the Estimator](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Freplacing-the-estimator)\n- [Rate Limiting](\u002Fopen-source\u002Fpackages\u002Fshipping-estimate-plugin\u002Fdocs\u002F1.x\u002Frate-limiting)\n",{"name":6,"slug":7,"previousSlugs":26,"description":10,"github":27,"packagistName":14,"packageType":15,"hasDocumentation":16,"supported":16,"visible":16,"versions":28},[9],{"owner":12,"repo":13},[29],{"version":19,"gitBranch":20,"released":21},{"version":19,"gitBranch":20,"released":21},1790077875370]