+
Skip to content

Fulfillment feature #6480

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

Closed
wants to merge 47 commits into from
Closed

Fulfillment feature #6480

wants to merge 47 commits into from

Conversation

sujithvn
Copy link
Contributor

@sujithvn sujithvn commented Sep 20, 2022

Signed-off-by: Sujith mail.sujithvn@gmail.com

Resolves #6471
Impact: breaking
Type: feature

Issue

In the current system, the only way for order fulfillment is via shipping which is hardcoded into the system. We need to introduce the flexibility for users to add their own fulfillment types via plugins.

Solution

We are creating a base fulfillment plugin which would enable other fulfillment types (like shipping, pickup, digital) to be introduced via plugins. Each of the newly introduced fulfillment type plugin would need to have the specific fulfillment methods also to be added as separate plugins. Example, fulfillment type 'pickup' could have fulfillment methods like 'store pickup' and 'curb-side pickup'.

Breaking changes

Since this is the new way of handling fulfillment, the existing shipment plugins would not work along with this. User would need to migrate the data (migration script will be developed) and remove the shipment plugins (api-plugin-shipments and api-plugin-shipments-flat-rate).

Testing

To perform review and testing of the related code changes, we are adding details related to this feature implementation which spans across multiple plugins (each in its own folders in the packages folder in monorepo).

At a high level the impacted plugins are:

Existing plugin changes

api-plugin-products
api-plugin-catalogs
api-plugin-carts
api-plugin-orders

Plugins to be removed

api-plugin-shipments
api-plugin-shipments-flat-rate

New Plugins to be added

api-plugin-fulfillment
api-plugin-fulfillment-type-shipping
api-plugin-fulfillment-method-shipping-flat-rate
api-plugin-fulfillment-method-shipping-ups
api-plugin-fulfillment-type-pickup
api-plugin-fulfillment-method-pickup-store

Changes in detail:

CARTS
  • New field - cartVersion in the cart to identify the new carts. Old carts will not have this field
  • New field - selectedFulfillmentType: This field allows UI to send the fulfillment-type selected by user for the product while adding to the cart. This is optional and if not selected the item would default to undecided fulfillment group.
  • New field - supportedFulfillmentTypes: This field was supposed to be existing but was missing. Added now (bug fix).
  • New Mutation - setFulfillmentTypeForItems: Accepts an array of itemIds and a selected fulfillment type along with cart details. This mutation would move all the provided items to the requested fulfillment group depending on conditions like FFtype is supported by product, FFtype is active etc.
  • Exported ShippingMethod & Shipment from SimpleSchema - these schemas will be extended in the api-plugin-fulfillment plugin to have the allowedValues changed from the hard coded "shipping" to dynamic array containing all the installed FFTypes
  • New field - fulfillmentMethod - This is field will be non-editable and used for matching the fulfillment method from other functions/calls. Matching on existing fields like 'name' which are user-input in flat-rate method is not reliable.
  • New field - displayMessageMethod - This new field will hold any string to be displayed along the FF Method in the UI, example store pickup requesting user to come in only after 24hrs of ordering.
  • New field - methodAdditionalData: This could be fulfillment specific information used for processing in the system. Example Store may provide store details.
  • updateCartFulfillmentGroups: logic updated - when new item is added to cart, if "selectedFulfillmentType" is provided, we add to that group, else the item goes to "Undecided" group.
CATALOGS
  • supportedFulfillmentTypes - this field will be extended in the api-plugin-fulfillment plugin to have the allowedValues changed from the hard coded "shipping" to dynamic array containing all the installed FFTypes
PRODUCTS
  • supportedFulfillmentTypes - this field will be extended in the api-plugin-fulfillment plugin to have the allowedValues changed from the hard coded "shipping" to dynamic array containing all the installed FFTypes
ORDERS
  • Exported CommonOrder, orderFulfillmentGroupInputSchema, SelectedFulfillmentOption - these schemas will be extended in the api-plugin-fulfillment plugin to have the allowedValues changed from the hard coded "shipping" to dynamic array containing all the installed FFTypes
  • New field - methodAdditionalData: This could be fulfillment specific information used for processing in the system. Example Store may provide store details.
    (above 2 changes are spread across multiple files)
ORDERS (specific to placeOrder refactor and introduction of validateOrder end-point)
  • Moved out most of the functionalities from placeOrder to prepareOrder.
  • Flattened out the hierarchical function calls by 1-2 levels and placed all the called functions in folder orderValidators inside util. Most of the functions are copied over from existing code base.
  • prepareOrder builds up the order object and performs the validation steps in parallel. Validation results are accumulated in an array for most of the errors except the initial 2-3 errors where we return with the error.
  • Both placeOrder and validateOrder calls prepareOrder with respective flags.
  • Few steps specifically are related to payments auth and are skipped in case validateOrder is calling prepareOrder.
  • In case of validateOrder call, most of the function calls are placed in a try-catch block to collect the errors. In case of placeOrder call, functions are directly executed.
  • Final order object is validated against the schema (in case of prepare order, it is validated against a custom schema).
  • prepareOrder returns Order & token to placeOrder, and returns success flag and validationResults to validateOrder.
  • placeOrder will finally insert the order returned by prepareOrder into the DB and completes the placing of order.
API-PLUGIN-FULFILLMENT

This is the base plugin, basic features listed below.
Mutations

  • createFulfillmentType - this is for internal call only from ff-type plugins (NEW)
  • createFulfillmentMethod - this is for internal call only from ff-method plugins (NEW)
  • updateFulfillmentType - public mutation which allows to update certain specific fields of the ff-type (NEW)
  • updateFulfillmentMethod - public mutation which allows to update certain specific fields of the ff-type (NEW)
  • updateFulfillmentOptionsForGroup - Existing code/functionality from the old shipment plugin. This updates the cart with quote details from all available ff-methods for the provided ff-type
  • selectFulfillmentOptionForGroup - Existing code/functionality from the old shipment plugin. This updates the cart with one of the selected ff-method from the available quote presented by above mutation.

Queries

  • getFulfillmentMethodsWithQuotes - Existing code/functionality from the old shipment plugin. Calls the quote providing functions by collecting them via functionByType. Calls are made only for the specific methods of the provided ff-type.
  • getFulfillmentType - returns the ff-type matching the provided ID (NEW)
  • getFulfillmentTypes - returns all the ff-types (NEW)
  • getFulfillmentMethods - returns all the ff-methods for the specified ff-type (NEW)

Others

  • preStartup - extends all impacted schemas mostly with dynamic values for 'allowedValues' (NEW)
  • startup - inserts the default 'undecided' entry to the new Fulfillment collection (NEW)
  • registration - collects all the "registeredFulfillmentType" from ff-type plugins and adds allRegisteredFulfillmentTypes to context (contextAddition) (NEW)
  • util folder - copied over from shipment plugin (Existing code)
API-PLUGIN-FULFILLMENT-TYPE-SHIPPING
  • Registers the 'shipping' as a ff-type via registeredFulfillmentTypes: ["shipping"]
  • Inserts the default entry for shipping ff-type in Fulfillment collection
API-PLUGIN-FULFILLMENT-TYPE-PICKUP
  • Registers the 'pickup' as a ff-type via registeredFulfillmentTypes: ["pickup"]
  • Inserts the default entry for pickup ff-type in Fulfillment collection
API-PLUGIN-FULFILLMENT-METHOD-SHIPPING-FLAT-RATE
  • Mostly copied over from api-plugin-shipment-flat-rate by making certain fixes to adhere to new structure and new DB collections. Fixes are similar to the details provided for the other 2 ff-method plugins below.
  • The mutations & queries present were left as it is and it works slightly differently compared to the new mutations/queries that were introduced in api-plugin-fulfillment (which is used by remaining ff-methods)
  • Shipping restrictions feature is copied over from existing code. This feature is not added to other ff-methods.
API-PLUGIN-FULFILLMENT-METHOD-SHIPPING-UPS
  • getFulfillmentMethodsWithQuotesShippingUPS - returns the quote or equivalent details for the method when called from base ff plugin
  • preStartup - extends the union of "methodAdditionalData" with data structure specific to UPS
  • startup - Inserts the required ff-method entry into Fulfillment collection
  • util/calculateUPSRate - dummy function to simulate api providing UPS specific info while returning quotes.
  • util/ validateOrderMethodsups - dummy function to simulate UPS specific validations done. Called by prepareOrder.js
API-PLUGIN-FULFILLMENT-METHOD-PICKUP-STORE
  • getFulfillmentMethodsWithQuotesPickupStore - returns the quote or equivalent details for the method when called from base ff plugin
  • preStartup - extends the union of "methodAdditionalData" with data structure specific to Store
  • startup - Inserts the required ff-method entry into Fulfillment collection
  • util/collectStoreDetails - dummy function to simulate api providing Store specific info while returning quotes.
  • util/ validateOrderMethodsstore - dummy function to simulate Store specific validations done. Called by prepareOrder.js

Test cases

With the above changes, we should be able to test the following cases:

  1. The current code base has 2 ff-types and 3 ff-methods implemented. We could add more by following the same template (pref type-pickup, method-store). New ff-type should register itself similar to registration.js and insert the base entry in Fulfillment collection. New ff-method should have the functionalities that provide quotes/equivalent with additional data if any, validation results (refer method-store-ups).
  2. Use "createCart" endpoint to create a new cart and add an item. If the "selectedFulfillmentType" is provided in the input, a fulfillment group of that ff-type will be created. Else the item will be placed in "undecided" group.
  3. More items could be added to the cart using the "addCartItems" endpoint. Here also we could optionally include the "selectedFulfillmentType". All items belonging to one ff-type will be grouped together.
  4. We can use endpoint "setFulfillmentTypeForItems" to re-assign the items in "undecided" group to any of the selected ff-group.
  5. Use "updateFulfillmentOptionsForGroup" to update the cart with quote details from all available ff-methods for the provided ff-type and then subsequently use "selectFulfillmentOptionForGroup" to select one of them as the selected ff-method for the ff-group.
  6. Place the order as usual by providing the "selectedFulfillmentMethodId" for each of the ff-group created. Order should be placed successfully
  7. validateOrder endpoint could be used to verify the correctness & completeness of the input to placeOrder prior to actually placing the order.

Pending items

The below pending items will be introduced via separate PR/tickets

  • Documentation providing details of the Fulfillment features for a UI team
  • i18n feature
  • Data migration
  • Feature to split order resulting in multiple groups for same ff-type
  • Enable default ff-type for products

setFulfillmentType, methodAdditionalData, cartVersion

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
supportedFFTypes allowedValues to dynamic array in FFT-base

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
supportedFFTypes allowedValues to dynamic array in FFT-base

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
supportedFFTypes allowedValues to FFT-base and methodAdditionalData

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
new endpoint validateOrder & refactored placeOrder

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit of the base api-plugin-fulfillment

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit of the api-plugin-fulfillment-type-shipping

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit for api-plugin-fulfillment-type-pickup

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit of the api-plugin-fulfillment-pickup-store

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit of the api-plugin-fulfillment-method-shipping-ups

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
First commit - api-plugin-fulfillment-shipping-flat-rate

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
@sujithvn sujithvn changed the title Sujith/monorepo Fulfillment feature Sep 21, 2022
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
@changeset-bot
Copy link

changeset-bot bot commented Sep 27, 2022

⚠️ No Changeset found

Latest commit: d90a43d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
@sujithvn sujithvn marked this pull request as ready for review September 27, 2022 12:16
@brent-hoover brent-hoover changed the base branch from feat/monorepo to trunk September 29, 2022 07:50
@brent-hoover brent-hoover changed the base branch from trunk to feat/fulfillment-types September 29, 2022 07:51
@brent-hoover brent-hoover requested a review from aldeed September 29, 2022 08:41
Copy link
Collaborator

@brent-hoover brent-hoover left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly changes around style. Will test more tomorrow

@@ -0,0 +1,70 @@
# api-plugin-fulfillment-method-shipping-ups
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am uncomfortable with calling this shipping-ups since it doesn't actually implement UPS. I would rather it be called something like "dynamic-rate"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, if we are planning to expand this to a more functional (and less dummy) plugin, then we could try out ups as the first option and retain the name.
If that is not the plan, we can change the name as you have suggested.

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
Signed-off-by: Sujith <mail.sujithvn@gmail.com>
@tedraykov tedraykov self-requested a review October 6, 2022 11:31
Copy link
Collaborator

@tedraykov tedraykov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the PR partially. It's quite a daunting task to review within days something that's been developed for months. Eventually will get to it :)

if (!cart.cartVersion) {
supportedFulfillmentTypes = ["shipping"]; // we use 'shipping' as default fulfillment type for old v1 carts (prior to fulfillment types)
} else {
throw new ReactionError("not-found", "Product does not have any supported FulfillmentTypes");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the supportedFulfillmentType on a product and on a catalog is not mandatory. This causes the supportedFulfillmentTypes to be an empty array by default (packages/api-plugin-products/src/mutations/createProduct.js)

We always will hit this error when adding to cart products that didn't had explicit supportedFulfillmentTypes set. We either have to make the CreateProductInput.supportedFulfillmentTypes required, or provide a default list of types. Otherwise, the system can get into an invalid state.

The invariant of the product catalog is that it should always have at least one supported ff type. If it doesn't, it cannot be fulfilled by any method and therefore it shouldn't be visible in the first place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a separate PR (#6543) which helps the admin to set base ff-types and these ff-types would get added to all new products along with (any) user provided ff-types.

Signed-off-by: Sujith <mail.sujithvn@gmail.com>
@@ -14,26 +14,30 @@
"accounts": "@reactioncommerce/api-plugin-accounts",
"authentication": "@reactioncommerce/api-plugin-authentication",
"authorization": "@reactioncommerce/api-plugin-authorization-simple",
"products": "@reactioncommerce/api-plugin-products",
"catalogs": "@reactioncommerce/api-plugin-catalogs",
"products": "../../packages/api-plugin-products/index.js",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use @reactioncommerce/... for all plugins including new ones.


const pickupRecord = await Fulfillment.findOne({ fulfillmentType: "pickup", shopId });
if (!pickupRecord) {
const groupInfo = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw this code duplicated on other fulfillment types. could this be done in a declarative way via register function? I saw the same pattern for fulfillment methods too.
cc: @zenweasel

Comment on lines +53 to +60
rates.push({
carrier,
handlingPrice: updatedMethod.handling,
method: updatedMethod,
rate: updatedMethod.rate,
shippingPrice: updatedMethod.rate + updatedMethod.handling,
shopId: doc.shopId
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be done in a declarative way too?

each method will provide a function that returns new rates.
the root plugin will collect all of rates to return so we won't have previousQueryResults

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are collecting rates from multiple methods under same ff-type. We also give each method more than one chance to return the rates (since they could be fetched from external systems). So if initial fetch attempt fails, they are added into retrialTargets

@sujithvn
Copy link
Contributor Author

This PR is replaced by PR#6480

@sujithvn sujithvn closed this May 24, 2023
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

Successfully merging this pull request may close these issues.

As a user, I should be able to checkout with multiple fulfillment types in a single order using the new set of plugins
4 participants
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载