Skip to content

Instantly share code, notes, and snippets.

@machty
Created August 19, 2020 16:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save machty/b7037e297b6e87920dd727084684a57f to your computer and use it in GitHub Desktop.
Save machty/b7037e297b6e87920dd727084684a57f to your computer and use it in GitHub Desktop.
diff --git a/app/models/checkout_location.rb b/app/models/checkout_location.rb
index 0a017d1ed..9b1e82deb 100644
--- a/app/models/checkout_location.rb
+++ b/app/models/checkout_location.rb
@@ -196,11 +196,9 @@ class CheckoutLocation < ApplicationRecord
demo_reasons.present?
end
- SHOPPABLE_STATUSES = %i[ready demo].freeze
def ready_for_shopping?
- setup_statuses.values.all? do |value|
- SHOPPABLE_STATUSES.include?(value)
- end
+ setup_statuses[:inventory_adapter] == :ready &&
+ setup_statuses[:payment_adapters] == :ready
end
def setup_statuses
diff --git a/app/models/fpr_cron_parser.rb b/app/models/fpr_cron_parser.rb
new file mode 100644
index 000000000..51954d9fa
--- /dev/null
+++ b/app/models/fpr_cron_parser.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class FprCronParser
+ attr_reader :cron_string, :cron_parser, :time_zone
+
+ def self.for(full_cron_string)
+ return nil unless full_cron_string.present?
+
+ new(full_cron_string)
+ end
+
+ def initialize(full_cron_string)
+ @cron_string, zone_str = full_cron_string.split('|').map(&:strip)
+ zone_str ||= "UTC"
+ @time_zone = ActiveSupport::TimeZone[zone_str]
+ @cron_parser = CronParser.new(@cron_string, time_zone)
+ end
+
+ def next(time)
+ cron_parser.next(time.in_time_zone(time_zone))
+ end
+
+ def last(time)
+ cron_parser.last(time.in_time_zone(time_zone))
+ end
+
+ def summary
+ "#{Cronex::ExpressionDescriptor.new(cron_string).description} - #{time_zone}"
+ end
+end
diff --git a/app/models/http_utility.rb b/app/models/http_utility.rb
index 877396106..c6ea07686 100644
--- a/app/models/http_utility.rb
+++ b/app/models/http_utility.rb
@@ -1,20 +1,35 @@
# frozen_string_literal: true
class HttpUtility
- attr_accessor :log_user_events, :source, :redact, :httparty_options
+ attr_accessor :log_http_interactions, :source, :redact, :httparty_options
DEFAULT_TIMEOUT_SECONDS = 15
class SSLCertificateExpiresSoon < BugsnaggableError; end
WARN_EXPIRING_CERTIFICATES_WITHIN = 3.weeks
- def initialize(source: nil, log_user_events: true, redact: nil, **httparty_options)
+ def initialize(source: nil, log_http_interactions: true, use_static_ip: false, redact: nil, **httparty_options)
self.redact = [redact].flatten.map(&:presence).compact
- self.log_user_events = log_user_events
+ self.log_http_interactions = log_http_interactions
self.source = source
self.httparty_options = {
timeout: DEFAULT_TIMEOUT_SECONDS,
- }.merge(httparty_options)
+ }.merge(static_ip_options(use_static_ip))
+ .merge(httparty_options)
+ end
+
+ def static_ip_options(use_static_ip)
+ if use_static_ip && proxy_url = ENV['FIXIE_URL'].presence
+ uri = URI.parse(proxy_url)
+ {
+ http_proxyaddr: uri.host,
+ http_proxyport: uri.port,
+ http_proxyuser: uri.user,
+ http_proxypass: uri.password,
+ }
+ else
+ {}
+ end
end
%i[get patch post put].each do |method|
@@ -26,7 +41,7 @@ class HttpUtility
end
end
- def log_user_event(url:, success:, duration:, post_body:, response_body:, code:, error:)
+ def log_http_interaction(url:, success:, duration:, post_body:, response_body:, code:, error:)
HttpInteraction.create_async(
source: source,
url: truncate_and_redact(url),
@@ -68,10 +83,10 @@ class HttpUtility
def log_result(url, options, response:, duration:, error:)
success = !!response&.success?
- return unless log_user_events
- return if success && log_user_events == :error
+ return unless log_http_interactions
+ return if success && log_http_interactions == :error
- log_user_event(
+ log_http_interaction(
url: url,
success: success,
duration: duration,
diff --git a/app/models/inventory_adapter.rb b/app/models/inventory_adapter.rb
index 461d6d913..29fca9c20 100644
--- a/app/models/inventory_adapter.rb
+++ b/app/models/inventory_adapter.rb
@@ -14,6 +14,7 @@ module InventoryAdapter
FPRAdapter,
RetailCloudAdapter,
ColruytAdapter,
+ ::Inventory,
]
end
diff --git a/app/models/inventory_adapter/fpr_adapter.rb b/app/models/inventory_adapter/fpr_adapter.rb
index 4a385661b..e723e4df4 100644
--- a/app/models/inventory_adapter/fpr_adapter.rb
+++ b/app/models/inventory_adapter/fpr_adapter.rb
@@ -3,6 +3,7 @@
module InventoryAdapter
class FPRAdapter < ApplicationRecord # rubocop:disable Metrics/ClassLength
include SharedAdapterMethods
+ include SharedFPRAdapterMethods
include LoyaltySupport
auto_strip_attributes :api_key
validates :api_key, presence: true, uniqueness: { scope: :inventory_adapter_fpr_adapter_host_id }
@@ -38,47 +39,6 @@ module InventoryAdapter
end
end
- def lookup_descriptor(desc)
- estimation = estimate(adds: [desc])
- failure = estimation.failures.first
-
- if failure
- return nil unless failure['reason'] == 'needs_weight'
-
- line_item = extract_line_item_from_needs_weight_failure(failure)
- else
- line_item = estimation.line_item_collection.first
- end
-
- ItemData.new(
- name: line_item.name,
- code: line_item.upc,
- kind: determine_item_data_kind(line_item),
- price_per: (line_item.price_per unless line_item.price_per.zero?),
- weight: line_item.weight,
- requires: determine_item_data_requires(failure, line_item),
- allow_negative: allow_negative_adjustments?,
- )
- end
-
- def determine_item_data_requires(failure, line_item)
- if failure
- "weight"
- elsif line_item.transaction_type == "department"
- "price"
- else
- "quantity"
- end
- end
-
- def determine_item_data_kind(line_item)
- if line_item.transaction_type == "department"
- "department"
- else
- "normal"
- end
- end
-
def allow_negative_adjustments?
# Fairway is the only client using department listing, and
# they requested negative adjustments to be disabled.
@@ -161,27 +121,14 @@ module InventoryAdapter
InventoryAdapter::FPRAdapter::Request.new(self)
end
- def extract_line_item_from_needs_weight_failure(failure_hash)
- FPRAdapter::CartSerializer.line_item_from_item_hash(failure_hash)
- end
-
def perform_remote_estimation(request)
- items_payload, translations = make_items_payload(request)
- params = {
- items: items_payload,
- loyalties: request.loyalties,
- external_id: request.external_id,
- source_type: request.source_type,
- source_id: request.source_id,
- started_at: request.started_at&.iso8601,
- }
- make_request.post(
- 'estimates',
- params,
- ).tap do |resp|
+ wrap_fpra_estimate(request) do |payload|
+ resp = make_request.post(
+ 'estimates',
+ payload,
+ )
raise_estimation_error(StandardError.new(resp.body)) unless resp.success?
- end.as_json.tap do |response_payload|
- restore_original_scan_codes(response_payload, translations)
+ resp.as_json
end
end
@@ -213,84 +160,5 @@ module InventoryAdapter
response = http_utility.post(url, body: request.serialize(:oj))
st::CONTAINER.deserialize(:oj, "FprAdapterEstimateResponse", response.body)
end
-
- def perform_estimation(request)
- resp = perform_remote_estimation(request)
- estimate_hash = resp.fetch('estimate')
- line_item_collection = FPRAdapter::CartSerializer.line_item_collection_from_adapter_payload(
- estimate_hash,
- )
- failures = resp.fetch('failures') || []
- estimation_attributes = {
- request: request,
- line_item_collection: line_item_collection,
- failures: failures,
- alerts: coupon_alerts(line_item_collection, request),
- tax_info: estimate_hash['tax_info'],
- tlog_data: estimate_hash['tlog_data'],
- external_id: estimate_hash['external_id'],
- possible_loyalty: failures.map { |f| f['found_loyalty'] }.compact.first,
- }.merge(loyalty_estimation_attributes(resp))
- Estimation.new(estimation_attributes)
- rescue EOFError, SocketError => e
- raise_estimation_error(e)
- end
-
- def restore_original_scan_codes(response_payload, translations)
- response_payload['estimate']['items'].each do |item|
- client_id = item['client_id']
- if original_code = translations[client_id]
- item['client_code'] = original_code
- end
- end
- end
-
- def coupon_alerts(line_item_collection, request)
- if (code = request.adds.first&.code) &&
- !request.removes&.length.positive? &&
- line_item_collection.coupons.find { |c| c.client_code == code }
- [AppAlert.find_by(key: 'shopper_added_coupon').as_json]
- else
- []
- end
- end
-
- def raise_estimation_error(e)
- raise ::InventoryAdapter::EstimationError, "Bad Estimation Request: #{e.class} #{e.message}"
- end
-
- def make_items_payload(request)
- payload = []
- translations = {}
-
- request.source_descriptors.each do |descriptor|
- payload << descriptor_as_json(descriptor, translations)
- end
-
- [payload, translations]
- end
-
- def translate_code(code)
- EpcPureIdentity.detect_from_scan(code)&.to_barcode_key
- end
-
- def descriptor_as_json(desc, translations)
- code = desc.code
- if translated_code = translate_code(code)
- translations[desc.client_id] = code
- code = translated_code
- end
-
- desc.lookup_params || {
- "code" => code,
- "client_id" => desc.client_id,
- "wgt" => desc.weight.as_json,
- }.tap do |h|
- if desc.item_type == 'department'
- h["amount"] = desc.amount.format
- h["type"] = 'department'
- end
- end
- end
end
end
diff --git a/app/models/inventory_adapter/fpr_adapter/loyalty_support.rb b/app/models/inventory_adapter/fpr_adapter/loyalty_support.rb
index 54403eabb..a1b8c02cc 100644
--- a/app/models/inventory_adapter/fpr_adapter/loyalty_support.rb
+++ b/app/models/inventory_adapter/fpr_adapter/loyalty_support.rb
@@ -38,10 +38,6 @@ module InventoryAdapter
"fpr-adapter-host/#{inventory_adapter_fpr_adapter_host_id}/#{slug}"
end
- def loyalty_estimation_attributes(resp)
- { loyalties: resp.dig('estimate', 'loyalties') || [] }
- end
-
private
def make_loyalty_result(data)
diff --git a/app/models/inventory_adapter/shared_fpr_adapter_methods.rb b/app/models/inventory_adapter/shared_fpr_adapter_methods.rb
new file mode 100644
index 000000000..0672a178b
--- /dev/null
+++ b/app/models/inventory_adapter/shared_fpr_adapter_methods.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: true
+
+module InventoryAdapter
+ module SharedFPRAdapterMethods
+ extend ActiveSupport::Concern
+
+ def perform_estimation(request)
+ resp = perform_remote_estimation(request)
+ estimate_hash = resp.fetch('estimate')
+ line_item_collection = FPRAdapter::CartSerializer.line_item_collection_from_adapter_payload(
+ estimate_hash,
+ )
+ failures = resp.fetch('failures') || []
+ estimation_attributes = {
+ request: request,
+ line_item_collection: line_item_collection,
+ failures: failures,
+ alerts: coupon_alerts(line_item_collection, request),
+ tax_info: estimate_hash['tax_info'],
+ tlog_data: estimate_hash['tlog_data'],
+ external_id: estimate_hash['external_id'],
+ possible_loyalty: failures.map { |f| f['found_loyalty'] }.compact.first,
+ }.merge(loyalty_estimation_attributes(resp))
+ Estimation.new(estimation_attributes)
+ rescue EOFError, SocketError => e
+ raise_estimation_error(e)
+ end
+
+ def coupon_alerts(line_item_collection, request)
+ if (code = request.adds.first&.code) &&
+ !request.removes&.length.positive? &&
+ line_item_collection.coupons.find { |c| c.client_code == code }
+ [AppAlert.find_by(key: 'shopper_added_coupon').as_json]
+ else
+ []
+ end
+ end
+
+ def raise_estimation_error(e)
+ raise ::InventoryAdapter::EstimationError, "Bad Estimation Request: #{e.class} #{e.message}"
+ end
+
+ def wrap_fpra_estimate(request)
+ payload, translations = make_remote_estimation_payload(request)
+ yield(payload).tap do |response_payload|
+ restore_original_scan_codes(response_payload, translations)
+ end
+ end
+
+ def restore_original_scan_codes(response_payload, translations)
+ response_payload['estimate']['items'].each do |item|
+ client_id = item['client_id']
+ if original_code = translations[client_id]
+ item['client_code'] = original_code
+ end
+ end
+ end
+
+ def make_remote_estimation_payload(request)
+ items_payload, translations = make_items_payload(request)
+ payload = {
+ items: items_payload,
+ loyalties: request.loyalties,
+ external_id: request.external_id,
+ source_type: request.source_type,
+ source_id: request.source_id,
+ started_at: request.started_at&.iso8601,
+ }
+ [payload, translations]
+ end
+
+ def make_items_payload(request)
+ payload = []
+ translations = {}
+
+ request.source_descriptors.each do |descriptor|
+ payload << descriptor_as_json(descriptor, translations)
+ end
+
+ [payload, translations]
+ end
+
+ def translate_code(code)
+ EpcPureIdentity.detect_from_scan(code)&.to_barcode_key
+ end
+
+ def loyalty_estimation_attributes(resp)
+ { loyalties: resp.dig('estimate', 'loyalties') || [] }
+ end
+
+ def descriptor_as_json(desc, translations)
+ code = desc.code
+ if translated_code = translate_code(code)
+ translations[desc.client_id] = code
+ code = translated_code
+ end
+
+ desc.lookup_params || {
+ "code" => code,
+ "client_id" => desc.client_id,
+ "wgt" => desc.weight.as_json,
+ }.tap do |h|
+ if desc.item_type == 'department'
+ h["amount"] = desc.amount.format
+ h["type"] = 'department'
+ end
+ end
+ end
+
+ def lookup_descriptor(desc)
+ estimation = estimate(adds: [desc])
+ failure = estimation.failures.first
+
+ if failure
+ return nil unless failure['reason'] == 'needs_weight'
+
+ line_item = extract_line_item_from_needs_weight_failure(failure)
+ else
+ line_item = estimation.line_item_collection.first
+ end
+
+ ItemData.new(
+ name: line_item.name,
+ code: line_item.upc,
+ kind: determine_item_data_kind(line_item),
+ price_per: (line_item.price_per unless line_item.price_per.zero?),
+ weight: line_item.weight,
+ requires: determine_item_data_requires(failure, line_item),
+ allow_negative: allow_negative_adjustments?,
+ )
+ end
+
+ def extract_line_item_from_needs_weight_failure(failure_hash)
+ FPRAdapter::CartSerializer.line_item_from_item_hash(failure_hash)
+ end
+
+ def determine_item_data_requires(failure, line_item)
+ if failure
+ "weight"
+ elsif line_item.transaction_type == "department"
+ "price"
+ else
+ "quantity"
+ end
+ end
+
+ def determine_item_data_kind(line_item)
+ if line_item.transaction_type == "department"
+ "department"
+ else
+ "normal"
+ end
+ end
+ end
+end
diff --git a/app/models/inventory_adapter/test_adapter.rb b/app/models/inventory_adapter/test_adapter.rb
index db537ae34..66a82154c 100644
--- a/app/models/inventory_adapter/test_adapter.rb
+++ b/app/models/inventory_adapter/test_adapter.rb
@@ -88,10 +88,14 @@ module InventoryAdapter
end
def self.build_inventory
- Dir.glob("config/test_inventory/*.yml").map do |path|
- YAML.load_file(path).map do |item|
- item.symbolize_keys.merge(upc: item['upc'].gsub(/^0+/, ''))
- end
+ inventory_data.map do |item|
+ item.symbolize_keys.merge(upc: item['upc'].gsub(/^0+/, ''))
+ end
+ end
+
+ def self.inventory_data
+ @inventory_data ||= Dir.glob("config/test_inventory/*.yml").map do |path|
+ YAML.load_file(path)
end.flatten
end
diff --git a/app/models/inventory_adapter/test_estimator.rb b/app/models/inventory_adapter/test_estimator.rb
index da48e2bff..204f83a97 100644
--- a/app/models/inventory_adapter/test_estimator.rb
+++ b/app/models/inventory_adapter/test_estimator.rb
@@ -160,7 +160,7 @@ module InventoryAdapter
found_item.clone(
price: price,
prediscount_price: price,
- upc: nil,
+ upc: found_item.upc,
lookup_params: lookup.lookup_params || {
"type" => "department",
"code" => lookup.code,
diff --git a/app/models/slack_notifier.rb b/app/models/slack_notifier.rb
index 9d900b07d..e702f72b6 100644
--- a/app/models/slack_notifier.rb
+++ b/app/models/slack_notifier.rb
@@ -76,7 +76,7 @@ class SlackNotifier
protected
def http_utility
- HttpUtility.new(log_user_events: :error, redact: WEBHOOKS)
+ HttpUtility.new(log_http_interactions: :error, redact: WEBHOOKS)
end
def fulfillment_app_notification(order_department, text)
diff --git a/app/models/transaction_log/item.rb b/app/models/transaction_log/item.rb
index f5e81be36..ace9f0a9a 100644
--- a/app/models/transaction_log/item.rb
+++ b/app/models/transaction_log/item.rb
@@ -39,7 +39,17 @@ module TransactionLog
visaelectron
vpay
unionpay
- ]
+ ], _prefix: :subtype
+
+ NON_CARD_PAYMENT_TYPES = %w[
+ non_tender fpr_credit deferred unknown
+ ].freeze
+
+ CARD_PAYMENT_TYPES = (TransactionLog::Item.transaction_subtypes.keys - NON_CARD_PAYMENT_TYPES).freeze
+
+ def card_payment?
+ CARD_PAYMENT_TYPES.include?(transaction_subtype)
+ end
enum price_source: %i[unknown inventory scan_code], _prefix: :price_source
enum weight_source: %i[unknown user price scan_code], _prefix: :weight_source
@@ -82,6 +92,18 @@ module TransactionLog
end
end
+ def cart_item?
+ coded_item? || department?
+ end
+
+ def item_id
+ line_number
+ end
+
+ def parent_item_id
+ parent_ref
+ end
+
def self.build_items_from_order(order)
[
convert_cart_items_to_tlog_items_full(order),
diff --git a/app/models/transaction_log/order.rb b/app/models/transaction_log/order.rb
index 69068d1df..eb3be0bf0 100644
--- a/app/models/transaction_log/order.rb
+++ b/app/models/transaction_log/order.rb
@@ -2,10 +2,18 @@
module TransactionLog
class Order < ActiveRecord::Base
+ extend Memoist
has_many :transaction_log_items, class_name: "TransactionLog::Item",
foreign_key: :transaction_log_order_id,
inverse_of: :transaction_log_order,
dependent: :destroy
+ belongs_to :transaction_log_job, class_name: "TransactionLog::Job",
+ foreign_key: :transaction_log_job_id,
+ optional: true
+ belongs_to :transaction_log_upload_batch,
+ class_name: "TransactionLog::UploadBatch",
+ foreign_key: :transaction_log_upload_batch_id,
+ optional: true
belongs_to :checkout_location
belongs_to :customer, optional: true
@@ -35,12 +43,47 @@ module TransactionLog
transacted_at: purchasable.checkout_completed_at,
started_at: purchasable.created_at,
customer_birthdate: purchasable.customer_birthdate,
+ external_id: purchasable.external_id,
+ tlog_data: purchasable.tlog_data,
).tap do |order|
order.transaction_log_items = TransactionLog::Item.build_items_from_order(order)
order.assign_item_attrs
end
end
+ def receipt
+ ReceiptBuilder.new.single_receipt(purchasable).receipt unless purchasable.micropayment?
+ end
+ memoize :receipt
+
+ def cart_items
+ transaction_log_items.select(&:cart_item?)
+ end
+
+ def coupon_items
+ transaction_log_items.select(&:coupon?)
+ end
+
+ def bottle_deposit_items
+ transaction_log_items.select(&:bottle_deposit?)
+ end
+
+ def tax_items
+ transaction_log_items.select(&:tax?)
+ end
+
+ def payment_items
+ transaction_log_items.select(&:payment?)
+ end
+
+ def external_coupon_items
+ transaction_log_items.select(&:external_coupon?)
+ end
+
+ def department_items
+ transaction_log_items.select(&:department?)
+ end
+
def self.log_purchasable_idempotent(purchasable)
order = generate(purchasable)
maybe_insert_order_idempotent(purchasable, order)
diff --git a/app/models/transaction_log/upload_batch.rb b/app/models/transaction_log/upload_batch.rb
new file mode 100644
index 000000000..03c7c59c1
--- /dev/null
+++ b/app/models/transaction_log/upload_batch.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module TransactionLog
+ class UploadBatch < ApplicationRecord
+ belongs_to :s3_tlog_target
+ belongs_to :inventory
+ belongs_to :s3_tlog_target
+ enum state: %i[pending uploaded]
+
+ has_many :transaction_log_orders,
+ class_name: "TransactionLog::Order",
+ foreign_key: :transaction_log_upload_batch_id,
+ inverse_of: :transaction_log_upload_batch
+
+ validates :upload_scheduled_at, presence: true
+ end
+end
diff --git a/app/models/world/inventories.rb b/app/models/world/inventories.rb
new file mode 100644
index 000000000..653749bbd
--- /dev/null
+++ b/app/models/world/inventories.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+class World
+ module Inventories
+ extend ActiveSupport::Concern
+
+ included do
+ define :inventory_group do |options|
+ attrs = {
+ name: "TestInventoryGroup",
+ price_order: options.fetch(:price_order, 0),
+ code_pattern_sources: "upc,ean13",
+ itemized_taxes: options.fetch(:itemized_taxes, true),
+ item_price_type: options.fetch(:item_price_type, "pre_tax_item_prices"),
+ ruleset_name: "fairway",
+ loyalty_discount_groups: {
+ "10": "0.1",
+ "12": "0.06",
+ "90": "0.2",
+ "91": "0.2",
+ },
+ }.merge(options)
+
+ InventoryGroup.create!(
+ attrs.merge(options),
+ )
+ end
+
+ define :inventory do |options|
+ Inventory.create!(
+ inventory_group: ensure_inventory_group,
+ name: 'TestInventory',
+ tax_rates: ensure_inventory_tax_rates_set,
+ additionals: ensure_inventory_additionals_set,
+ ).tap do |inventory|
+ ::InventoryAdapter::TestAdapter.inventory_data.each do |item_data|
+ import_from_yml(inventory, item_data)
+ end
+ end
+ end
+
+ def import_from_yml(inventory, item_data)
+ if item_data['type'] == 'department'
+ import_department_from_yml(inventory, item_data)
+ else
+ import_item_from_yml(inventory, item_data)
+ end
+ end
+
+ def import_department_from_yml(inventory, item_data)
+ inventory.departments.create!(
+ name: item_data['name'],
+ key: item_data['upc'],
+ discountable: !!item_data['discountable'],
+ tax_flags: item_data['tax_flags'],
+ department_code: item_data['upc'],
+ )
+ end
+
+ def import_item_from_yml(inventory, item_data)
+ price_per = (item_data['price_per'] || item_data['price']).to_money
+ normal_price_per = item_data['normal_price_per']&.to_money
+
+ normal_price_calculator = PriceCalculator::BasicPricing.new(price_per)
+ if normal_price_per
+ special_price_calculator = normal_price_calculator
+ normal_price_calculator = PriceCalculator::BasicPricing.new(normal_price_per)
+ end
+
+ inventory.items.create!(
+ name: item_data['name'],
+ key: item_data['upc'],
+ sold_by_weight: item_data['requires'] == 'weight',
+ normal_price_calculator: normal_price_calculator,
+ special_price_calculator: special_price_calculator || PriceCalculator::NullPricing.new,
+ discountable: !!item_data['discountable'],
+ tax_flags: item_data['tax_flags'],
+ department_code: item_data['department_code'],
+ tare_weight: (item_data['tare_weight'] || '0').to_d,
+ )
+ end
+
+ # TODO: this should probably be called `inventory_tax_rates` but it causes stack overflow
+ # issues with World's pluralization conventions
+ define :inventory_tax_rates_set do |_options|
+ [{ "name": "Sales Tax", "value": "0.08875", "tax_code": "A" }]
+ end
+
+ define :inventory_additionals_set do |_options|
+ [
+ {
+ 'name' => 'Bottle Deposit',
+ 'taxable' => false,
+ },
+ {
+ 'name' => 'Eco Fee',
+ 'taxable' => true,
+ },
+ ]
+ end
+ end
+ end
+end
diff --git a/app/models/world/inventory_adapter.rb b/app/models/world/inventory_adapter.rb
index a5e14d435..0ffafcb6f 100644
--- a/app/models/world/inventory_adapter.rb
+++ b/app/models/world/inventory_adapter.rb
@@ -53,6 +53,14 @@ class World
cashier_id: '1',
)
end
+
+ f.member :inline_inventory_adapter do |options|
+ if options.is_a?(::Inventory)
+ options
+ else
+ add(:inventory, options)
+ end
+ end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment