Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Warehouse Selection Algorithm for the Shipping #5

Closed
vrann opened this issue May 17, 2017 · 4 comments
Closed

Create Warehouse Selection Algorithm for the Shipping #5

vrann opened this issue May 17, 2017 · 4 comments

Comments

@vrann
Copy link
Contributor

vrann commented May 17, 2017

Overview

Multiple Nodes Inventory implies that the products will be stored in multiple locations. When Customer buys the product, it should be shipped from the particular location. A customer usually does not care what location product was shipped from, as soon as this is the cheapest option. For the Merchant, it is important to have minimal overhead for the inventory storage and shipping costs. An algorithm which assigns the particular inventory to the order item should take all these considerations into account and select the best possible options.

Use-Case

To visualize the process of the warehouse selection let's describe the following use-case. Customers create an Order to buy products A, B and C:

Product Qty
A 5
B 2
C 7

Merchant has following stock quantities in warehouses X, Y and Z

Product Warehouse Qty
A X 10
A Y 10
A Z 10
B X 1
B Y 1
B Z 1
C X 5
C Y 2
C Z 7

There are multiple possible options on how to fulfill the order:

  1. Ship 10xA from the Warehouse X, 1xB from the X and 1xB from Z, 5xC from the X and 2xC from Y
  2. Ship 5xA from X and 5xA from Y, 1xB from the X and 1xB from Z, 7xC from the Z
  3. etc

As you can see there are multiple possible strategies on how to optimize order fulfillment:

  • try to ship as much as possible from one warehouse. This minimizes packaging costs and possibly shipping cost
  • try to distribute the load between warehouses. This minimizes storage cost
  • select warehouse based on the cost of shipment to the merchant address for the particular Carrier
  • select warehouse based on the shipment time

The order fulfillment algorithm should pick the location of the product and use it to calculate the shipping cost.

Problem

Earlier implementations of MNI identified the problems with the advanced algorithms of the warehouse selection. For example, if the warehouse selected based on the delivery cost, for every possible combination of warehouses system should perform the API call to the carrier to retrieve the shipping cost.

Approach

It is impossible for the Magento platform to predict all the circumstances which affect inventory and shipping costs for the particular merchant. That's why instead of implementing all possible optimizations of the algorithm selection, the framework will contain the interface which is used to resolve the Source for the order item. Different implementations of the algorithm will contain
Implementations, provided by the 3-d party extensions will allow affecting the priorities of the warehouse selection depending on the particular case where Magento is used.

Magento framework will provide the default, rule-based algorithm which allows configuring the priority of warehouses depending on the source origin, shipping address and the selected carrier.

Interfaces

Following interface will be called by the Magento framework at the point of shipment calculation. Changing the implementation of the interface allows affecting the algorithm of the Warehouse resolution.

use Magento\Quote\Model\Quote\Address\RateRequest;

/**
 * SourceShippingResolverInterface
 */
interface SourceResolverInterface
{
    /**
     * Resolve source shipping data
     *
     * @param RateRequest $request
     * @param ShippingRateCalculator $shippingRateCalculator
     * @return array
     */
    public function resolve(RateRequest $request, ShippingRateCalculator $shippingRateCalculator);
}

Default Algorithm

Magento will allow creating rules of selecting the fulfillment warehouse based on following pieces of information:

  • warehouses addresses
  • customer shipping address
  • carrier

The rules will be defined in the format: (Customer State, Carrier) -> Warehouse
The rules will be configured in the CSV file and imported to the Magento.

Implementation Items

Following items need to be implemented in order to make Warehouse selection work in Magento:

  • Create interface of the Warehouse resolution
  • Inject interface to the Magento framework and use it during shipping rate calculation. Implement it for complex cases such as Bundle or Grouped products.
  • Make information on selected warehouse reflected on the Order and be available during the fulfillment
  • Implement default algorithm which works based on configured rules
  • implement import of rules via CSV File
@maghamed
Copy link
Contributor

Let's be consistent and use "Source" term instead of "Warehouse".
Also, this term doesn't align with "In Store Pick-up" functionality.

Some insight and performance degradation we had with Minimal delivery cost algorithm calculation. In our investigation, we made a half of year ago https://wiki.corp.magento.com/pages/viewpage.action?spaceKey=MAGE2&title=MNI+Multi+Node+Inventory+part+2.+HLD#MNIMultiNodeInventorypart2.HLD-Performanceissues
Results of investigation

we saw that we have a linear dependency on a number of products in the basket and amount of sources, so all together it gives us square law variation which would be killing for big merchants. But we have priority based algorithm which performance satisfies us. So, we have an idea to make “Minimal Delivery Cost” algorithm work like priority based. But priority would be not static (provided by merchant beforehand), but dynamic – chosen dependent on the delivery address and source address. All that we need is to sort sources in accordance to remoteness from the delivery address and then apply priority based algorithm. Taking as an assumption that shorter distance delivery will cost less than longer distance delivery. We don’t have Geo API and can’t calculate the distance from the source to the delivery address, but actually we no need it, moreover, distance is not always correct way, because delivery from the same State will cost less, even if the distance is longer.
Thus, we could just receive pairs of what States or Countries are close to another States/Countries and then just make a Topological Sorting https://en.wikipedia.org/wiki/Topological_sorting of sources based on delivery address. We use Topological sorting in Magento when specifying the dependency of modules on other modules (sequence) to sort them out in an order to get rid the situation when we install CatalogInventory module which dependent on Catalog, before the Catalog one. So, this is similar issue.

@maghamed
Copy link
Contributor

maghamed commented May 18, 2017

Description of how

  1. Priority
  2. Lowest cost using flat rate / table rate by source
    algorithms work right now:
    This should be part of Aceptance Criteria to Algorithm Story

https://wiki.corp.magento.com/display/MPD/%5BMNI%5D+Shipping+Rate+Algorithms

By Priority

Algorithm steps:

  1. Get list of sources sorted by priority (source attribute)
  2. Take all available products from 1st source by priority. If some of the products in the order couldn't be delivered from 1st source - get the rest of products from next by priority source.
    2.1. Repeat Step 2. until all the products from the order would be ready to shipping.

By Minimal Delivery Cost:

Algorithm steps:

Delivery to fulfill the order could be made from one or several (more than one) sources
1.1 Evaluate each source for one product delivery
1.2 Fulfill the order by minimal cost sources (result is sum of each value)
1.3 Recalculate shipping cost based on previous step result. Obtained value is displayed for customer.

Example 1. Each product item delivered from a single Source:

Pre-Condition:
Shopping Cart
Product A - 2 items
Product B - 2 items

Source 1 (Flat Rate - 10$)
Product A - 100 items
Product B - 100 items

Source 2 (Flat Rate - 15$)
Product A - 100 items
Product B - 100 items

Algorithm steps:

1.1) Collect all common sources (with delivery cost) for all products in shopping cart
2 Product A from Source 1 + 2 Product B from Source 1 = 10$
2 Product A from Source 2 + 2 Product B from Source 2 = 15$
1.2) We choose first combination with minimal cost
Result:
2 Product A from Source 1 + 2 Product B from Source 1 = 10$

Example 2 delivery made from several Sources:

Pre-Condition:
Shopping Cart
Product A - 2 items
Product B - 2 items

Source 1 (Flat Rate - 10$)
Product A - 100 items
Product B - 1 items

Source 2 (Flat Rate - 15$)
Product A - 100 items
Product B - 1 items

Algorithm steps:

1.1) Collect one product delivery cost for each source:
for Product A:
a) 1 Product A from Source 1 = 10$
b) 1 Product A from Source 2 = 15$
for Product B:
c) 1 Product B from Source 1 = 10$
d) 1 Product B from Source 2 = 15$
1.2) Fulfill the order by minimal cost sources
Result:
(2 * a) + (1 * c) + (1 * d)
1.3) Recalculation
We can see that we have two products going to be delivered from single stock, but we used Flat Rate cost twice. So we need to repeat calculation based on result from prev step:
25$ (this value is displayed for customer)

Example 3 without common Source (more complexity):

Pre-Condition:

Shopping Cart
Product A - 2 items
Product B - 3 items
Product C - 4 items

Source 1 (Flat Rate - 10$)
Product A - 100 items
Product B - 2 items
Product C - 2 items

Source 2 (Flat Rate - 15$)
Product A - 100 items
Product B - 2 items
Product C - 2 items

Algorithm steps:

1.1) Collect one product delivery cost for each source:
for Product A:
a) 1 Product A from Source 1 = 10$
b) 1 Product A from Source 2 = 15$
for Product B:
c) 1 Product B from Source 1 = 10$
d) 1 Product B from Source 2 = 15$
for Product C:
e) 1 Product C from Source 1 = 10$
f) 1 Product C from Source 2 = 15$
1.2) Fulfill the order by minimal cost sources

Result:
(2 * a) // Product A is fulfill

  • (2 * c) + (1 * d)
  • (2 * c) + (1 * d) // Product B is fulfill
  • (2 * e) + (2 * f) // Product C is fulfill
    1.3) Recalculation
    We can see that we have two products going to be delivered from single stock, but we used Flat Rate cost twice. So we need to repeat calculation based on result from prev step:
    25$ (this value is displayed for customer)

(this value is display for customer)

@maghamed
Copy link
Contributor

maghamed commented May 18, 2017

Additional AC:
Algorithm should support Asynchronous calculation

@vrann
Copy link
Contributor Author

vrann commented May 18, 2017

@vrann vrann closed this as completed May 18, 2017
naydav pushed a commit that referenced this issue Mar 21, 2018
…ile creating new customer … #5 #14204

 - Merge Pull Request magento/magento2#14204 from rostyslav-hymon/magento2:2.3-develop-PR-port-13024
 - Merged commits:
   1. 255b682
   2. e37ae24
naydav pushed a commit that referenced this issue Mar 21, 2018
naydav pushed a commit that referenced this issue Mar 21, 2018
naydav pushed a commit that referenced this issue Mar 21, 2018
Accepted Public Pull Requests:
 - magento/magento2#14210: [Forwardport] Inconsistent Redirect in Admin Notification Controller (by @dimonovp)
 - magento/magento2#14209: [Forwardport] Invoice grid shows wrong subtotal for partial items invoice. It shows order's subtotal instead if invoiced item's subtotal (by @AlexWorking)
 - magento/magento2#14207: [Forwardport] Make scope parameters of methods to save/delete config optional (by @mastiuhin-olexandr)
 - magento/magento2#14205: [Forwardport] Allow changing head and body element through xml layout updates (by @dimonovp)
 - magento/magento2#14204: [Forwardport] resolved default country selection issue while creating new customer � #5 (by @rostyslav-hymon)
 - magento/magento2#14203: [Forwardport] Use event object in 'ajax:addToCart' trigger when adding a product to the cart (by @mastiuhin-olexandr)
 - magento/magento2#14199: [Forwardport] Issue-13768 Fixed error messages on admin user account page after redirect for force password change (by @dimonovp)
 - magento/magento2#14194: [Forwardport] [FIX] small refactoring and removing not using variable from templates (by @mastiuhin-olexandr)
 - magento/magento2#14192: [Forwardport] magento/magento2#13820: IE11 minicart not updating on configurable pr� (by @mastiuhin-olexandr)
 - magento/magento2#14191: [Forwardport] Removed unnecessary protected member variables. (by @dimonovp)
 - magento/magento2#14190: [Forwardport] Modify Report processor to return 500 (by @AlexWorking)
 - magento/magento2#14185: [Forwardport] Added missing event parameter for proxy function on the search form submit (by @dimonovp)
 - magento/magento2#14184: [Forwardport] Add @api annotation to block argument marker interface (by @dimonovp)
 - magento/magento2#14214: [Forwardport] Fix $useCache for container child blocks (by @rostyslav-hymon)
 - magento/magento2#14212: [Forwardport] Fix typo in securityCheckers array (by @AlexWorking)
 - magento/magento2#14215: [Forwardport] #13899 Solve Canada Zip Code pattern (by @AlexWorking)
 - magento/magento2#14216: [Forwardport] Fix cache issue for currencies with no symbol (by @dimonovp)
 - magento/magento2#14213: [Forwardport] Added alias to block 'product.info.description' (by @mastiuhin-olexandr)


Fixed GitHub Issues:
 - magento/magento2#13804: Invoice grid shows wrong subtotal for partial items invoice. It shows order's subtotal instead if invoiced item's subtotal (reported by @ankurvr) has been fixed in magento/magento2#14209 by @AlexWorking in 2.3-develop branch
   Related commits:
     1. 0bfc3e1

 - magento/magento2#4454: CMS Page with <head> in layout update xml (reported by @zhiyicai) has been fixed in magento/magento2#14205 by @dimonovp in 2.3-develop branch
   Related commits:
     1. 822c6e9

 - magento/magento2#3483: Default country selection issue while creating new customer from backend (reported by @keyurshah070) has been fixed in magento/magento2#14204 by @rostyslav-hymon in 2.3-develop branch
   Related commits:
     1. 255b682
     2. e37ae24

 - magento/magento2#13768: Expired backend password - Attention: Something went wrong (reported by @janssensjelle) has been fixed in magento/magento2#14199 by @dimonovp in 2.3-develop branch
   Related commits:
     1. 4df41e1

 - magento/magento2#13820: IE11 minicart not updating on configurable product page (ES6) (reported by @Pumppa) has been fixed in magento/magento2#14192 by @mastiuhin-olexandr in 2.3-develop branch
   Related commits:
     1. 6d4065a

 - magento/magento2#11512: Incorrect use of 503 status code (reported by @andrewhowdencom) has been fixed in magento/magento2#14190 by @AlexWorking in 2.3-develop branch
   Related commits:
     1. 72c502f

 - magento/magento2#13791: Submitting search form (mini) with empty value throws error on preventDefault (reported by @koenner01) has been fixed in magento/magento2#14185 by @dimonovp in 2.3-develop branch
   Related commits:
     1. 808487b

 - magento/magento2#13899: Postal code (zip code) for Canada should allow postal codes without space (reported by @sl02) has been fixed in magento/magento2#14215 by @AlexWorking in 2.3-develop branch
   Related commits:
     1. c87b104
     2. ac37727
     3. bda63c7
     4. cb04f93
RomaKis pushed a commit that referenced this issue Mar 22, 2018
removed request_schema attribute added in previous commits
sidolov pushed a commit that referenced this issue May 8, 2020
MQE-2076: [PHPUnit 9] assertEquals and assertNotEquals optional parameters removed
mmansoor-magento pushed a commit that referenced this issue Oct 21, 2020
[Arrows] Fixes for 1.2-develop (pr1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants