diff --git a/modules/field/commerce_cost_field.libraries.yml b/modules/field/commerce_cost_field.libraries.yml
new file mode 100644
index 0000000..09c2439
--- /dev/null
+++ b/modules/field/commerce_cost_field.libraries.yml
@@ -0,0 +1,10 @@
+sale_price:
+  version: 1.x
+  css:
+    theme:
+      css/sale_price_calculation.css: {}
+  js:
+    js/sale_price_calculation.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupalSettings
diff --git a/modules/field/config/schema/commerce_cost_field.schema.yml b/modules/field/config/schema/commerce_cost_field.schema.yml
new file mode 100644
index 0000000..7b22de5
--- /dev/null
+++ b/modules/field/config/schema/commerce_cost_field.schema.yml
@@ -0,0 +1,10 @@
+field.widget.settings.commerce_price_with_cost:
+  type: mapping
+  label: 'Field selection'
+  mapping:
+    price_field:
+      type: string
+      label: 'Commerce price field'
+    cost_field:
+      type: string
+      label: 'Commerce cost field'
diff --git a/modules/field/css/sale_price_calculation.css b/modules/field/css/sale_price_calculation.css
new file mode 100644
index 0000000..881424c
--- /dev/null
+++ b/modules/field/css/sale_price_calculation.css
@@ -0,0 +1,4 @@
+.commerce-cost-value-changed {
+  background-color: #f0ff00 !important;
+  color: #366097;
+}
diff --git a/modules/field/js/sale_price_calculation.js b/modules/field/js/sale_price_calculation.js
new file mode 100644
index 0000000..2738576
--- /dev/null
+++ b/modules/field/js/sale_price_calculation.js
@@ -0,0 +1,72 @@
+/**
+ * @file
+ * Defines sale price based off product price, cost and markup.
+ */
+(function ($, Drupal) {
+  'use strict';
+
+  Drupal.behaviors.commerce_cost_calculation = {
+    attach: function (context, settings) {
+      var markupClass = 'field--name-field-markup-percentage';
+      var priceClass = '.field--name-' + drupalSettings.commerce_cost_field.price_field;
+      var costClass = '.field--name-' + drupalSettings.commerce_cost_field.cost_field;
+
+      // Commerce price DOM elements.
+      var $markup = '';
+      var $price = $(priceClass).find('input');
+      var $cost = $(costClass).find('input');
+
+      // The markup textfield.
+      var markupElement = '<label for="markup-percentage" class="markup-field-label">Markup percentage</label>';
+      markupElement += '<input type="text" size="10" id="markup-percentage" class="form-text ' + markupClass + '">';
+      markupElement += '<span class="field-suffix">%</span>';
+      $markup = $(markupElement);
+      if ($('#markup-percentage').length === 0) {
+        $markup.insertAfter($(costClass));
+      }
+      markupClass = '.' + markupClass;
+      $markup = $(markupClass);
+
+      // Default value for already set product's margin.
+      if ($cost.val() !== '' && $price.val() !== '') {
+        var value = ((($price.val() - $cost.val()) / $cost.val()) * 100).toFixed(2);
+        $markup.val(value);
+      }
+
+      // Cost and Markup fields changed - set price.
+      $cost.add($markup).on('keyup', function() {
+        if ($cost.val() !== '' && $markup.val() !== '') {
+          var priceNumber = $price.get(0);
+          var value = $cost.val() * (1 + $markup.val() / 100);
+          animateTextField($(priceNumber), value);
+        }
+      });
+
+      // Price field changed - set markup.
+      $price.on('keyup', function() {
+        if ($price.val() !== '' && $cost.val() !== '') {
+          var value = (($price.val() - $cost.val()) / $cost.val()) * 100;
+          animateTextField($markup, value);
+        }
+      });
+
+      /**
+       * Provide an animation on textfields highlighting value change.
+       */
+      function animateTextField($obj, val) {
+        var value = val.toFixed(2);
+        if (!isNaN(value)) {
+          $obj
+            .val(value)
+            .addClass('commerce-cost-value-changed');
+
+          setTimeout(function() {
+            $obj.removeClass('commerce-cost-value-changed');
+          }, 500);
+        }
+      }
+
+    }
+  };
+
+})(jQuery, Drupal);
diff --git a/modules/field/src/Plugin/Field/FieldWidget/PriceWithCostWidget.php b/modules/field/src/Plugin/Field/FieldWidget/PriceWithCostWidget.php
new file mode 100644
index 0000000..26e6d57
--- /dev/null
+++ b/modules/field/src/Plugin/Field/FieldWidget/PriceWithCostWidget.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\commerce_cost_field\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Plugin implementation of the 'commerce_price_with_cost' widget.
+ *
+ * @FieldWidget(
+ *   id = "commerce_price_with_cost",
+ *   label = @Translation("Price with Cost"),
+ *   field_types = {
+ *     "commerce_price"
+ *   }
+ * )
+ */
+class PriceWithCostWidget extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    return [
+      'price_field' => '',
+      'cost_field' => '',
+    ] + parent::defaultSettings();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form = parent::settingsForm($form, $form_state);
+
+    $options = [];
+    $entity_type = $this->fieldDefinition->getTargetEntityTypeId();
+    $bundle = $this->fieldDefinition->getTargetBundle();
+    if (empty($bundle)) {
+      return $options;
+    }
+
+    $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle);
+    /** @var \Drupal\field\Entity\FieldConfig $field */
+    foreach ($fields as $field) {
+      if ($field->getType() === 'commerce_price') {
+        $options[$field->getName()] = $field->getLabel() . ' (' . $field->getName() . ')';
+      }
+    }
+
+    $form['price_field'] = [
+      '#type' => 'select',
+      '#options' => $options,
+      '#title' => $this->t('Select Commerce price field'),
+      '#default_value' => $options,
+    ];
+    $form['cost_field'] = [
+      '#type' => 'select',
+      '#options' => $options,
+      '#title' => $this->t('Select Cost price field'),
+      '#default_value' => $this->getSetting('cost_field'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
+    $element['#type'] = 'commerce_price';
+    $element['#available_currencies'] = array_filter($this->getFieldSetting('available_currencies'));
+
+    // Attach the library.
+    $form['#attached']['library'][] = 'commerce_cost_field/sale_price';
+    $form['#attached']['drupalSettings']['commerce_cost_field'] = [
+      'price_field' => str_replace('_', '-', $this->settings['price_field']),
+      'cost_field' => str_replace('_', '-', $this->settings['cost_field']),
+    ];
+
+    if (!$items[$delta]->isEmpty()) {
+      $element['#default_value'] = $items[$delta]->toPrice()->toArray();
+    }
+
+    return $element;
+  }
+
+}
diff --git a/src/OrderProcessor/ApplyCost.php b/src/OrderProcessor/ApplyCost.php
index ccbf623..c63958a 100644
--- a/src/OrderProcessor/ApplyCost.php
+++ b/src/OrderProcessor/ApplyCost.php
@@ -38,7 +38,9 @@ class ApplyCost implements OrderProcessorInterface {
     $context = new Context($order->getCustomer(), $order->getStore());
     foreach ($order->getItems() as $orderItem) {
       $cost = $this->chainCostResolver->resolve($orderItem->getPurchasedEntity(), $orderItem->getQuantity(), $context);
-      $orderItem->set('field_cost', $cost);
+      if ($orderItem->hasField('field_cost')) {
+        $orderItem->set('field_cost', $cost);
+      }
     }
   }
 
