Warning
You are browsing the documentation for the new Sharetribe Web Template. If you are using FTW-daily, hourly or product, see the legacy documentation.

Last updated

How to customize pricing

Flex allows lots of flexibility for your providers in terms of how they can set their pricing. This guide walks you through customizing listing pricing and commission.

Table of Contents

This how-to guide shows you how listing pricing can be customized by using two examples: adding an insurance fee to a bookable listing, and changing provider commission so that it's based on booking length. The changes we are about to make are as follows:

  1. Update rental listing data model by storing insurance fee price in listing public data
  2. Update pricing logic to add a insurance fee line item if a listing has insurance fee stored in public data
  3. Update provider commission calculation to be dependent on booking length

For more information about pricing in Flex, see the Pricing background article.

1. Listing extended data

Pricing can be based on a lot of variables, but one practical way to build it is to base it on information stored as extended data in listings. See the Extend listing data in Sharetribe Web Template how-to guide to read how to extend the listing data model with extended data. See the same guide for instructions how to add inputs for new attributes in the listing wizard. Alternatively, in order to try out this guide, you can just add a hard-coded insurance fee to the EditListingPricingPanel component:

└── src
    └── containers
        └── EditListingPricingPage
            └── EditListingPricingWizard
        └── EditListingPricingPanel
            └── EditListingPricingPanel.js

Booking and product related transaction processes have different pricing panels, since the product process uses the EditListingPricingAndStockPanel component. This means that adding the insurance fee to the EditListingPricingPanel only adds it to bookable listings.

However, we may want to set a different insurance fee for hourly listings and daily or nightly listings.

On submit, save price and insuranceFee:

+ import { HOUR } from '../../../../transactions/transaction';
...
 const form = priceCurrencyValid ? (
   <EditListingPricingForm
     className={css.form}
     initialValues={{ price }}
-    onSubmit={onSubmit}
+    const insuranceFeeAmount = unitType === HOUR ? 500 : 2000;
+    onSubmit={values => {
+      const { price } = values;
+      const updatedValues = {
+         price,
+         publicData: {
+           insuranceFee: { amount: insuranceFeeAmount, currency: marketplaceCurrency },
+         }
+      };
+      onSubmit(updatedValues);
+    }}
     onChange={onChange}
     saveActionMsg={submitButtonText}
     disabled={disabled}

2. Transaction line item for insurance fee

As the previous section mentions, this guide expects that the insurance fee price is stored in listing public data in an object with two keys: amount and currency. The amount attribute holds the price in subunits whereas currency holds the currency code. For example, with a cleaning fee of $20 the subunit amount is 2000 cents.

const insuranceFeeAmount = unitType === HOUR ? 500 : 2000;
...
publicData: {
    insuranceFee: { amount: insuranceFeeAmount, currency: marketplaceCurrency },
}

Flex pricing uses privileged transitions to ensure flexible pricing models while keeping control of the pricing logic in a secure environment. Transitioning requests of privileged transitions are made from the server-side. Thus we'll need to update the pricing logic in the /server/api-util/lineItems.js file:

└── server
    └── api-util
        └── lineItems.js

In the helper function section of the file, add a function that resolves the insurance fee of a listing:

const resolveInsuranceFeePrice = listing => {
  const { amount, currency } =
    listing.attributes.publicData?.insuranceFee || {};

  if (amount && currency) {
    return new Money(amount, currency);
  }

  return null;
};

Now the transactionLineItems function can be updated to also provide the insurance fee line item in case the listing has an insurance fee configured:

const insuranceFeePrice = resolveInsuranceFeePrice(listing);
const insuranceFeeLineItem = insuranceFeePrice
  ? [
      {
        code: 'line-item/insurance-fee',
        unitPrice: insuranceFeePrice,
        quantity: 1,
        includeFor: ['customer', 'provider'],
      },
    ]
  : [];

// Note: extraLineItems for product selling (aka shipping fee)
// is not included to commission calculation.
const providerCommission = {
  code: 'line-item/provider-commission',
  unitPrice: calculateTotalFromLineItems([order, ...insuranceFee]),
  percentage: PROVIDER_COMMISSION_PERCENTAGE,
  includeFor: ['provider'],
};

// Let's keep the base price (order) as first line item and provider's commission as last one.
// Note: the order matters only if OrderBreakdown component doesn't recognize line-item.
const lineItems = [
  order,
  ...extraLineItems,
  ...insuranceFee,
  providerCommission,
];

Now, if you open up a bookable listing page and select dates in the order panel on the right, the template will fetch line items and you will see an insurance fee row in the order breakdown:

Booking panel

Note, that the order breakdown automatically renders the insurance fee line item by tokenizing the line item code and capitalizing the first letter. In case this is not enough, you can add your own presentational line item component to the booking breakdown. This is done by adding the line item code (in our case line-item/insurance-fee) into the LINE_ITEMS array in src/util/types.js and creating your own LineItem*Maybe component to be used in OrderBreakdown.

3. Dynamic provider commission

Now that we've updated the pricing logic based on listing extended data, let's next update the provider commission based on the booking length.

The idea is to keep the 10% commission for bookings of 5 or less nights. For bookings of more than 5 nights, we'll set the provider commission to 7%. Update the transactionLineItems function in lineItems.js as follows:

 const PROVIDER_COMMISSION_PERCENTAGE = -10;
+const PROVIDER_COMMISSION_PERCENTAGE_REDUCED = -7;
const commissionPercentage =
  quantity > 5
    ? PROVIDER_COMMISSION_PERCENTAGE_REDUCED
    : PROVIDER_COMMISSION_PERCENTAGE;
const commissionPercentage =
  quantity > 5
    ? PROVIDER_COMMISSION_PERCENTAGE_REDUCED
    : PROVIDER_COMMISSION_PERCENTAGE;

// Note: extraLineItems for product selling (aka shipping fee)
//       is not included to commission calculation.
const providerCommission = {
  code: 'line-item/provider-commission',
  unitPrice: calculateTotalFromLineItems([order, ...insuranceFee]),
  percentage: commissionPercentage,
  includeFor: ['provider'],
};

Now when the provider takes a look at a pricing breakdown of a booking longer than 5 nights, the commission is calculated with 7% instead of 10%:

Provider breakdown