mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-15 19:06:50 +00:00
Compare commits
26 Commits
v5.0.4
...
RachL-patc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5020cc740 | ||
|
|
7a2a6fab21 | ||
|
|
0f4ca50d0e | ||
|
|
3ec8cd24d3 | ||
|
|
d0dcc92ca7 | ||
|
|
22f3afc7f7 | ||
|
|
46048dcd18 | ||
|
|
a8fb6492f4 | ||
|
|
4610141ed8 | ||
|
|
8098131dba | ||
|
|
597d9ad314 | ||
|
|
1ce0b25bb0 | ||
|
|
c07ec6cdfd | ||
|
|
48e8ad3dd0 | ||
|
|
60d4cd60ff | ||
|
|
d62d3041b4 | ||
|
|
42fc0f7230 | ||
|
|
39fa8e0ace | ||
|
|
d9809fc1f4 | ||
|
|
528c851e89 | ||
|
|
8709c137c7 | ||
|
|
355541e8de | ||
|
|
e10c3dc59b | ||
|
|
641b7beee3 | ||
|
|
60e8db9adc | ||
|
|
b7285e48b3 |
@@ -28,7 +28,7 @@ class AmendBackorderJob < ApplicationJob
|
||||
urls = FdcUrlBuilder.new(reference_link)
|
||||
orderer = FdcBackorderer.new(user, urls)
|
||||
|
||||
backorder = orderer.find_open_order
|
||||
backorder = orderer.find_open_order(order)
|
||||
|
||||
variants = order_cycle.variants_distributed_by(distributor)
|
||||
adjust_quantities(order_cycle, user, backorder, urls, variants)
|
||||
|
||||
@@ -13,7 +13,7 @@ class BackorderJob < ApplicationJob
|
||||
sidekiq_options retry: 0
|
||||
|
||||
def self.check_stock(order)
|
||||
links = SemanticLink.where(variant_id: order.line_items.select(:variant_id))
|
||||
links = SemanticLink.where(subject: order.variants)
|
||||
|
||||
perform_later(order) if links.exists?
|
||||
rescue StandardError => e
|
||||
@@ -133,5 +133,7 @@ class BackorderJob < ApplicationJob
|
||||
.perform_later(
|
||||
user, order.distributor, order.order_cycle, placed_order.semanticId
|
||||
)
|
||||
|
||||
order.exchange.semantic_links.create!(semantic_id: placed_order.semanticId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,12 +19,18 @@ class CompleteBackorderJob < ApplicationJob
|
||||
# someone else's order.
|
||||
def perform(user, distributor, order_cycle, order_id)
|
||||
order = FdcBackorderer.new(user, nil).find_order(order_id)
|
||||
|
||||
return if order&.lines.blank?
|
||||
|
||||
urls = FdcUrlBuilder.new(order.lines[0].offer.offeredItem.semanticId)
|
||||
|
||||
variants = order_cycle.variants_distributed_by(distributor)
|
||||
adjust_quantities(order_cycle, user, order, urls, variants)
|
||||
|
||||
FdcBackorderer.new(user, urls).complete_order(order)
|
||||
|
||||
exchange = order_cycle.exchanges.outgoing.find_by(receiver: distributor)
|
||||
exchange.semantic_links.find_by(semantic_id: order_id)&.destroy!
|
||||
rescue StandardError
|
||||
BackorderMailer.backorder_incomplete(user, distributor, order_cycle, order_id).deliver_later
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class StockSyncJob < ApplicationJob
|
||||
|
||||
def self.catalog_ids(order)
|
||||
stock_controlled_variants = order.variants.reject(&:on_demand)
|
||||
links = SemanticLink.where(variant_id: stock_controlled_variants.map(&:id))
|
||||
links = SemanticLink.where(subject: stock_controlled_variants)
|
||||
semantic_ids = links.pluck(:semantic_id)
|
||||
semantic_ids.map do |product_id|
|
||||
FdcUrlBuilder.new(product_id).catalog_url
|
||||
|
||||
@@ -22,6 +22,10 @@ class Exchange < ApplicationRecord
|
||||
has_many :exchange_fees, dependent: :destroy
|
||||
has_many :enterprise_fees, through: :exchange_fees
|
||||
|
||||
# Links to open backorders of a distributor (outgoing exchanges only)
|
||||
# Don't allow removal of distributor from OC while we have an open backorder.
|
||||
has_many :semantic_links, as: :subject, dependent: :restrict_with_error
|
||||
|
||||
validates :sender_id, uniqueness: { scope: [:order_cycle_id, :receiver_id, :incoming] }
|
||||
|
||||
before_destroy :delete_related_exchange_variants, prepend: true
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
# Link a Spree::Variant to an external DFC SuppliedProduct.
|
||||
class SemanticLink < ApplicationRecord
|
||||
belongs_to :variant, class_name: "Spree::Variant"
|
||||
self.ignored_columns += [:variant_id]
|
||||
|
||||
belongs_to :subject, polymorphic: true
|
||||
|
||||
validates :semantic_id, presence: true
|
||||
end
|
||||
|
||||
@@ -67,8 +67,12 @@ module Spree
|
||||
class_name: 'Spree::Adjustment',
|
||||
dependent: :destroy
|
||||
has_many :invoices, dependent: :restrict_with_exception
|
||||
|
||||
belongs_to :order_cycle, optional: true
|
||||
has_one :exchange, ->(order) {
|
||||
outgoing.to_enterprise(order.distributor)
|
||||
}, through: :order_cycle, source: :exchanges
|
||||
has_many :semantic_links, through: :exchange
|
||||
|
||||
belongs_to :distributor, class_name: 'Enterprise', optional: true
|
||||
belongs_to :customer, optional: true
|
||||
has_one :proxy_order, dependent: :destroy
|
||||
|
||||
@@ -60,7 +60,7 @@ module Spree
|
||||
has_many :exchanges, through: :exchange_variants
|
||||
has_many :variant_overrides, dependent: :destroy
|
||||
has_many :inventory_items, dependent: :destroy
|
||||
has_many :semantic_links, dependent: :delete_all
|
||||
has_many :semantic_links, as: :subject, dependent: :delete_all
|
||||
has_many :supplier_properties, through: :supplier, source: :properties
|
||||
|
||||
localize_number :price, :weight
|
||||
|
||||
@@ -10,7 +10,7 @@ class FdcBackorderer
|
||||
end
|
||||
|
||||
def find_or_build_order(ofn_order)
|
||||
find_open_order || build_new_order(ofn_order)
|
||||
find_open_order(ofn_order) || build_new_order(ofn_order)
|
||||
end
|
||||
|
||||
def build_new_order(ofn_order)
|
||||
@@ -19,7 +19,37 @@ class FdcBackorderer
|
||||
end
|
||||
end
|
||||
|
||||
def find_open_order
|
||||
# Try the new method and fall back to old method.
|
||||
def find_open_order(ofn_order)
|
||||
lookup_open_order(ofn_order) || find_last_open_order
|
||||
end
|
||||
|
||||
def lookup_open_order(ofn_order)
|
||||
# There should be only one link at the moment but we may support
|
||||
# ordering from multiple suppliers one day.
|
||||
semantic_ids = ofn_order.semantic_links.pluck(:semantic_id)
|
||||
|
||||
semantic_ids.lazy
|
||||
# Make sure we select an order from the right supplier:
|
||||
.select { |id| id.starts_with?(urls.orders_url) }
|
||||
# Fetch the order from the remote DFC server, lazily:
|
||||
.map { |id| find_order(id) }
|
||||
.compact
|
||||
# Just in case someone completed the order without updating our database:
|
||||
.select { |o| o.orderStatus[:path] == "Held" }
|
||||
.first
|
||||
# The DFC Connector doesn't recognise status values properly yet.
|
||||
# So we are overriding the value with something that can be exported.
|
||||
&.tap { |o| o.orderStatus = "dfc-v:Held" }
|
||||
end
|
||||
|
||||
# DEPRECATED
|
||||
#
|
||||
# We now store links to orders we placed. So we don't need to search
|
||||
# through all orders and pick a random open one.
|
||||
# But for compatibility with currently open order cycles that don't have
|
||||
# a stored link yet, we keep this method as well.
|
||||
def find_last_open_order
|
||||
graph = import(urls.orders_url)
|
||||
open_orders = graph&.select do |o|
|
||||
o.semanticType == "dfc-b:Order" && o.orderStatus[:path] == "Held"
|
||||
|
||||
@@ -9,6 +9,8 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
changePage(event) {
|
||||
const productsForm = document.querySelector("#products-form");
|
||||
productsForm.scrollIntoView({ behavior: "smooth" });
|
||||
this.page.value = event.target.dataset.page;
|
||||
this.submitSearch();
|
||||
this.page.value = 1;
|
||||
|
||||
@@ -1412,7 +1412,7 @@ en:
|
||||
connected_apps:
|
||||
legend: "Connected apps"
|
||||
affiliate_sales_data:
|
||||
title: "INRAE / UFC QUE CHOISIR Research"
|
||||
title: "INRAE Research"
|
||||
tagline: "Allow this research project to access your orders data anonymously"
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
@@ -1420,10 +1420,10 @@ en:
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
description_html: |
|
||||
<p>
|
||||
INRAE and UFC QUE CHOISIR are teaming up to study food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
INRAE are studiying food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://apropos.coopcircuits.fr/"
|
||||
<a href="https://pepr-sams.fr/2024/03/12/plat4terfood/"
|
||||
target="_blank"><b>Learn more about this research project</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
|
||||
@@ -1695,6 +1695,7 @@ en_FR:
|
||||
pack_by_customer: Pack By Customer
|
||||
pack_by_supplier: Pack By Supplier
|
||||
pack_by_product: Pack By Product
|
||||
pay_your_suppliers: Pay your suppliers
|
||||
display:
|
||||
report_is_big: "This report is big and may slow down your device."
|
||||
display_anyway: "Display anyway"
|
||||
@@ -1740,6 +1741,8 @@ en_FR:
|
||||
enterprise_fee_summary:
|
||||
name: "Enterprise Fee Summary"
|
||||
description: "Summary of Enterprise Fees collected"
|
||||
suppliers:
|
||||
name: Suppliers
|
||||
enterprise_fees_with_tax_report_by_order: "Enterprise Fees With Tax Report By Order"
|
||||
enterprise_fees_with_tax_report_by_producer: "Enterprise Fees With Tax Report By Producer"
|
||||
errors:
|
||||
@@ -3026,6 +3029,8 @@ en_FR:
|
||||
report_render_options: Rendering Options
|
||||
report_header_ofn_uid: OFN UID
|
||||
report_header_order_cycle: Order Cycle
|
||||
report_header_order_cycle_start_date: OC Start Date
|
||||
report_header_order_cycle_end_date: OC End Date
|
||||
report_header_user: User
|
||||
report_header_email: Email
|
||||
report_header_status: Status
|
||||
@@ -3046,6 +3051,7 @@ en_FR:
|
||||
report_header_hub_legal_name: "Hub Legal Name"
|
||||
report_header_hub_contact_name: "Hub Contact Name"
|
||||
report_header_hub_email: "Hub Public Email"
|
||||
report_header_hub_contact_email: Hub Contact Email
|
||||
report_header_hub_owner_email: Hub Owner Email
|
||||
report_header_hub_phone: "Hub Phone Number"
|
||||
report_header_hub_address_line1: "Hub Address Line 1"
|
||||
@@ -3118,6 +3124,8 @@ en_FR:
|
||||
report_header_producer_suburb: Producer Suburb
|
||||
report_header_producer_tax_status: Producer Tax Status
|
||||
report_header_producer_charges_sales_tax?: GST/VAT Registered
|
||||
report_header_producer_abn_acn: Producer ABN/ACN
|
||||
report_header_producer_address: Producer Address
|
||||
report_header_unit: Unit
|
||||
report_header_group_buy_unit_quantity: Group Buy Unit Quantity
|
||||
report_header_cost: Cost
|
||||
@@ -3178,7 +3186,11 @@ en_FR:
|
||||
report_header_total_units: Total Units
|
||||
report_header_sum_max_total: "Sum Max Total"
|
||||
report_header_total_excl_vat: "Total excl. tax (%{currency_symbol})"
|
||||
report_header_total_fees_excl_tax: "Total fees excl. tax (%{currency_symbol})"
|
||||
report_header_total_tax_on_fees: "Total tax on fees (%{currency_symbol})"
|
||||
report_header_total: "Total (%{currency_symbol})"
|
||||
report_header_total_incl_vat: "Total incl. tax (%{currency_symbol})"
|
||||
report_header_total_excl_fees_and_tax: "Total excl. fees and tax (%{currency_symbol})"
|
||||
report_header_temp_controlled: TempControlled?
|
||||
report_header_is_producer: Producer?
|
||||
report_header_not_confirmed: Not Confirmed
|
||||
|
||||
@@ -53,6 +53,7 @@ en_GB:
|
||||
primary_taxon: "Product Category"
|
||||
shipping_category_id: "Shipping Category"
|
||||
supplier: "Supplier"
|
||||
variant_unit: "Unit Scale"
|
||||
variant_unit_name: "Variant Unit Name"
|
||||
unit_value: "Unit value"
|
||||
spree/credit_card:
|
||||
@@ -80,6 +81,8 @@ en_GB:
|
||||
white_label_logo_link: "Link for the logo used in shopfront"
|
||||
errors:
|
||||
models:
|
||||
enterprise_fee:
|
||||
inherit_tax_requires_per_item_calculator: "Inheriting the tax category requires a per-item calculator."
|
||||
spree/image:
|
||||
attributes:
|
||||
attachment:
|
||||
@@ -104,6 +107,9 @@ en_GB:
|
||||
count_on_hand:
|
||||
using_producer_stock_settings_but_count_on_hand_set: "must be blank because using producer stock settings"
|
||||
limited_stock_but_no_count_on_hand: "must be specified because forcing limited stock"
|
||||
connected_apps:
|
||||
vine:
|
||||
api_request_error: "An error occured when connecting to Vine API"
|
||||
messages:
|
||||
confirmation: "doesn't match %{attribute}"
|
||||
blank: "can't be blank"
|
||||
@@ -315,7 +321,34 @@ en_GB:
|
||||
We will look into it but please let us know if the problem persists.
|
||||
backorder_mailer:
|
||||
backorder_failed:
|
||||
subject: "An automatic backorder failed"
|
||||
headline: "Backordering failed"
|
||||
description: |
|
||||
We tried to place or update a backorder for out-of-stock items but
|
||||
something went wrong. You may have negative stock and need to resolve
|
||||
the issue to order more stock in.
|
||||
hints: |
|
||||
You may need to go to the OIDC settings and reconnect your account.
|
||||
Also check that your supplier's catalog hasn't changed and is still
|
||||
supplying all products you need. And please get in touch with us if
|
||||
you have any questions.
|
||||
order: "Affected order: %{number}"
|
||||
stock: "Stock "
|
||||
product: "Product"
|
||||
backorder_incomplete:
|
||||
subject: "An automatic backorder failed to complete"
|
||||
headline: "Your backorder is still a draft"
|
||||
description: |
|
||||
We tried to complete a backorder for out-of-stock items but
|
||||
something went wrong. The backorder quantities may be too high if
|
||||
you had cancellations. And your backorder won't be fulfilled while
|
||||
it's in draft state.
|
||||
hints: |
|
||||
You may need to go to the OIDC settings and reconnect your account.
|
||||
Also check that your supplier's catalog hasn't changed and is still
|
||||
supplying all products you need. And please get in touch with us if
|
||||
you have any questions.
|
||||
affected: "%{enterprise}: %{order_cycle}"
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -554,10 +587,13 @@ en_GB:
|
||||
clone: Clone
|
||||
delete: Delete
|
||||
remove: Remove
|
||||
preview: Preview
|
||||
image:
|
||||
edit: Edit
|
||||
product_preview:
|
||||
product_preview: Product preview
|
||||
shop_tab: Shop
|
||||
product_details_tab: Product details
|
||||
adjustments:
|
||||
skipped_changing_canceled_order: "You can't change a cancelled order."
|
||||
begins_at: Begins At
|
||||
@@ -684,6 +720,7 @@ en_GB:
|
||||
connected_apps_enabled:
|
||||
discover_regen: Discover Regenerative portal
|
||||
affiliate_sales_data: DFC anonymised orders API for research purposes
|
||||
vine: Voucher Integration Engine (VINE)
|
||||
update:
|
||||
resource: Connected app settings
|
||||
customers:
|
||||
@@ -783,6 +820,7 @@ en_GB:
|
||||
variants:
|
||||
infinity: "Infinity"
|
||||
to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order."
|
||||
back_to_products_list: "Back To Products List"
|
||||
editing_product: "Editing Product"
|
||||
tabs:
|
||||
product_details: "Product Details"
|
||||
@@ -1303,11 +1341,21 @@ en_GB:
|
||||
connected_apps:
|
||||
legend: "Connected apps"
|
||||
affiliate_sales_data:
|
||||
title: "INRAE / UFC QUE CHOISIR Research"
|
||||
tagline: "Allow this research project to access your orders data anonymously"
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
loading: "Loading"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
description_html: |
|
||||
<p>
|
||||
INRAE and UFC QUE CHOISIR are teaming up to study food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://apropos.coopcircuits.fr/"
|
||||
target="_blank"><b>Learn more about this research project</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
discover_regen:
|
||||
title: "Discover Regenerative"
|
||||
tagline: "Allow Discover Regenerative to publish your enterprise information."
|
||||
@@ -1332,9 +1380,25 @@ en_GB:
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
vine:
|
||||
title: "Voucher Integration Engine (VINE)"
|
||||
tagline: "Allow redemption of VINE vouchers in your shopfront."
|
||||
enable: "Resources"
|
||||
disable: "Disconnect"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
vine_api_key: "VINE API Key"
|
||||
vine_secret: "VINE secret"
|
||||
description_html: |
|
||||
<p>
|
||||
To enable VINE for your enterprise, enter your API key and secret.
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" target="_blank"><b>VINE</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
api_parameters_empty: "Please enter an API key and a secret"
|
||||
api_parameters_error: "Check you entered your API key and secret correctly, contact your instance manager if the error persists"
|
||||
connection_error: "API connection error, please try again"
|
||||
setup_error: "VINE API is not configured, please contact your instance manager"
|
||||
actions:
|
||||
edit_profile: Settings
|
||||
properties: Properties
|
||||
@@ -1387,8 +1451,10 @@ en_GB:
|
||||
contact_name: Contact Name
|
||||
edit:
|
||||
editing: 'Settings:'
|
||||
back_link: Back To Enterprises List
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back To Enterprises List
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -1629,6 +1695,7 @@ en_GB:
|
||||
pack_by_customer: Pack By Customer
|
||||
pack_by_supplier: Pack By Supplier
|
||||
pack_by_product: Pack By Product
|
||||
pay_your_suppliers: Pay your suppliers
|
||||
display:
|
||||
report_is_big: "This report is big and may slow down your device."
|
||||
display_anyway: "Display anyway"
|
||||
@@ -1674,6 +1741,8 @@ en_GB:
|
||||
enterprise_fee_summary:
|
||||
name: "Enterprise Fee Summary"
|
||||
description: "Summary of Enterprise Fees collected"
|
||||
suppliers:
|
||||
name: Suppliers
|
||||
enterprise_fees_with_tax_report_by_order: "Enterprise Fees With Tax Report By Order"
|
||||
enterprise_fees_with_tax_report_by_producer: "Enterprise Fees With Tax Report By Producer"
|
||||
errors:
|
||||
@@ -2960,6 +3029,8 @@ en_GB:
|
||||
report_render_options: Rendering Options
|
||||
report_header_ofn_uid: OFN UID
|
||||
report_header_order_cycle: Order Cycle
|
||||
report_header_order_cycle_start_date: OC Start Date
|
||||
report_header_order_cycle_end_date: OC End Date
|
||||
report_header_user: User
|
||||
report_header_email: Email
|
||||
report_header_status: Status
|
||||
@@ -2980,6 +3051,7 @@ en_GB:
|
||||
report_header_hub_legal_name: "Hub Legal Name"
|
||||
report_header_hub_contact_name: "Hub Contact Name"
|
||||
report_header_hub_email: "Hub Public Email"
|
||||
report_header_hub_contact_email: Hub Contact Email
|
||||
report_header_hub_owner_email: Hub Owner Email
|
||||
report_header_hub_phone: "Hub Phone Number"
|
||||
report_header_hub_address_line1: "Hub Address Line 1"
|
||||
@@ -3052,6 +3124,8 @@ en_GB:
|
||||
report_header_producer_suburb: Producer Suburb
|
||||
report_header_producer_tax_status: Tax Rate Name
|
||||
report_header_producer_charges_sales_tax?: GST/VAT Registered
|
||||
report_header_producer_abn_acn: Producer ABN/ACN
|
||||
report_header_producer_address: Producer Address
|
||||
report_header_unit: Unit
|
||||
report_header_group_buy_unit_quantity: Group Buy Unit Quantity
|
||||
report_header_cost: Cost
|
||||
@@ -3112,7 +3186,11 @@ en_GB:
|
||||
report_header_total_units: Total Units
|
||||
report_header_sum_max_total: "Sum Max Total"
|
||||
report_header_total_excl_vat: "Total excl. tax (%{currency_symbol})"
|
||||
report_header_total_fees_excl_tax: "Total fees excl. tax (%{currency_symbol})"
|
||||
report_header_total_tax_on_fees: "Total tax on fees (%{currency_symbol})"
|
||||
report_header_total: "Total (%{currency_symbol})"
|
||||
report_header_total_incl_vat: "Total incl. tax (%{currency_symbol})"
|
||||
report_header_total_excl_fees_and_tax: "Total excl. fees and tax (%{currency_symbol})"
|
||||
report_header_temp_controlled: TempControlled?
|
||||
report_header_is_producer: Producer?
|
||||
report_header_not_confirmed: Not Confirmed
|
||||
@@ -3589,7 +3667,22 @@ en_GB:
|
||||
Please refresh the page and try again, if it fails a second time,
|
||||
please contact us for support.
|
||||
trix:
|
||||
bold: "Bold"
|
||||
bullets: "Bullets"
|
||||
code: "Code"
|
||||
heading1: "Heading"
|
||||
hr: "Horizontal rule"
|
||||
indent: "Increase Level"
|
||||
italic: "Italic"
|
||||
link: "Link"
|
||||
numbers: "Numbers"
|
||||
outdent: "Decrease Level"
|
||||
quote: "Quote"
|
||||
redo: "Redo"
|
||||
strike: "Strikethrough"
|
||||
undo: "Undo"
|
||||
unlink: "Unlink"
|
||||
url: "URL"
|
||||
urlPlaceholder: "Please enter a URL to insert"
|
||||
inflections:
|
||||
each:
|
||||
@@ -3902,6 +3995,7 @@ en_GB:
|
||||
tax_rate_amount_explanation: "Tax rates are a decimal amount to aid in calculations, (i.e. if the tax rate is 5% then enter 0.05)"
|
||||
included_in_price: "Included in Price"
|
||||
show_rate_in_label: "Show rate in label"
|
||||
back_to_tax_rates_list: "Back To Tax Rates List"
|
||||
tax_settings: "Tax Settings"
|
||||
zones: "Zones"
|
||||
new_zone: "New Zone"
|
||||
@@ -3914,6 +4008,7 @@ en_GB:
|
||||
iso_name: "ISO Name"
|
||||
states_required: "Counties Required"
|
||||
editing_country: "Editing Country"
|
||||
back_to_countries_list: "Back To Countries List"
|
||||
states: "Counties"
|
||||
abbreviation: "Abbreviation"
|
||||
new_state: "New County"
|
||||
@@ -4078,6 +4173,7 @@ en_GB:
|
||||
continue: "Continue"
|
||||
new:
|
||||
new_return_authorization: "New Return Authorisation"
|
||||
back_to_return_authorizations_list: "Back To Return Authorisations List"
|
||||
continue: "Continue"
|
||||
edit:
|
||||
receive: "receive"
|
||||
@@ -4290,6 +4386,8 @@ en_GB:
|
||||
new_product: "New Product"
|
||||
supplier: "Supplier"
|
||||
supplier_select_placeholder: "Select a supplier"
|
||||
search_for_suppliers: "Search for suppliers"
|
||||
search_for_units: "Search for units"
|
||||
product_name: "Product Name"
|
||||
units: "Unit Size"
|
||||
value: "Value"
|
||||
@@ -4406,6 +4504,7 @@ en_GB:
|
||||
total: "Total"
|
||||
billing_address_name: "Name"
|
||||
taxons:
|
||||
back_to_list: "Back To Product Categories List"
|
||||
index:
|
||||
title: "Product Categories"
|
||||
new_taxon: 'New product category'
|
||||
@@ -4416,6 +4515,7 @@ en_GB:
|
||||
destroy:
|
||||
delete_taxon:
|
||||
success: "Successfully deleted the product category"
|
||||
error: "Unable to delete the product category due to assigned products."
|
||||
form:
|
||||
name: Name
|
||||
meta_title: Meta Title
|
||||
|
||||
@@ -1697,6 +1697,7 @@ fr:
|
||||
pack_by_customer: Préparation des commandes par Acheteur
|
||||
pack_by_supplier: Préparation des commandes par Producteur
|
||||
pack_by_product: Préparation des commandes par Produit
|
||||
pay_your_suppliers: Payer vos fournisseurs
|
||||
display:
|
||||
report_is_big: "Ce rapport est volumineux et risque de ralentir l'appareil sur lequel vous êtes en train de le consulter."
|
||||
display_anyway: "Afficher quand même"
|
||||
@@ -1744,6 +1745,8 @@ fr:
|
||||
enterprise_fee_summary:
|
||||
name: "Résumé des marges et commissions"
|
||||
description: "Résumé des marges et commissions collectées"
|
||||
suppliers:
|
||||
name: Fournisseurs
|
||||
enterprise_fees_with_tax_report_by_order: "Détail des montants de taxe par commande"
|
||||
enterprise_fees_with_tax_report_by_producer: "Détail des montants de taxe par producteur"
|
||||
errors:
|
||||
@@ -3032,6 +3035,8 @@ fr:
|
||||
report_render_options: Mise en forme
|
||||
report_header_ofn_uid: ID OFN
|
||||
report_header_order_cycle: Cycle de Vente
|
||||
report_header_order_cycle_start_date: Date d'ouverture du cycle de vente
|
||||
report_header_order_cycle_end_date: Date de fermeture du cycle de vente
|
||||
report_header_user: Utilisateur
|
||||
report_header_email: Email
|
||||
report_header_status: Statut
|
||||
@@ -3052,6 +3057,7 @@ fr:
|
||||
report_header_hub_legal_name: "Raison sociale"
|
||||
report_header_hub_contact_name: "Nom du contact"
|
||||
report_header_hub_email: "Email public"
|
||||
report_header_hub_contact_email: e-mail de contact de la boutique multi-producteurs
|
||||
report_header_hub_owner_email: Email gestionnaire principal
|
||||
report_header_hub_phone: "Numéro de téléphone"
|
||||
report_header_hub_address_line1: "Adresse ligne 1"
|
||||
@@ -3124,6 +3130,8 @@ fr:
|
||||
report_header_producer_suburb: Ville Producteur
|
||||
report_header_producer_tax_status: Soumis à la TVA
|
||||
report_header_producer_charges_sales_tax?: Soumis à la TVA
|
||||
report_header_producer_abn_acn: Numéro de SIRET/SIREN du producteur
|
||||
report_header_producer_address: Adresse du producteur
|
||||
report_header_unit: Unité
|
||||
report_header_group_buy_unit_quantity: Nb d'unités achetées (vente par lots)
|
||||
report_header_cost: Coût
|
||||
@@ -3184,7 +3192,11 @@ fr:
|
||||
report_header_total_units: Vol. total
|
||||
report_header_sum_max_total: "Somme Max Total"
|
||||
report_header_total_excl_vat: "Total HT (%{currency_symbol})"
|
||||
report_header_total_fees_excl_tax: "Total commission boutique hors taxe (%{currency_symbol})"
|
||||
report_header_total_tax_on_fees: "Total taxe sur la commission boutique (%{currency_symbol})"
|
||||
report_header_total: "Total (%{currency_symbol})"
|
||||
report_header_total_incl_vat: "Total TTC (%{currency_symbol})"
|
||||
report_header_total_excl_fees_and_tax: "Total hors commission boutique et taxe (%{currency_symbol})"
|
||||
report_header_temp_controlled: Temp Contrôlée ?
|
||||
report_header_is_producer: Producteur ?
|
||||
report_header_not_confirmed: Non confirmé
|
||||
|
||||
4848
config/locales/sr.yml
Normal file
4848
config/locales/sr.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
class UpdateItemNameToProductInOdReport < ActiveRecord::Migration[7.0]
|
||||
class ReportRenderingOptions < ActiveRecord::Base
|
||||
self.belongs_to_required_by_default = false
|
||||
|
||||
belongs_to :user, class_name: "Spree::User"
|
||||
serialize :options, Hash, coder: YAML
|
||||
end
|
||||
|
||||
# OD: Orders and Distributors
|
||||
def up
|
||||
# adding subtype filter just to be safe
|
||||
options = ReportRenderingOptions.where(report_type: 'orders_and_distributors', report_subtype: nil)
|
||||
|
||||
options.find_each do |option|
|
||||
begin
|
||||
fields_to_show = option.options[:fields_to_show]
|
||||
next if fields_to_show&.exclude?('item_name')
|
||||
|
||||
fields_to_show.delete('item_name')
|
||||
fields_to_show << 'product'
|
||||
option.save
|
||||
rescue StandardError => e
|
||||
puts "Failed to update rendering option with id: #{option.id}"
|
||||
puts "Error: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
options = ReportRenderingOptions.where(report_type: 'orders_and_distributors', report_subtype: nil)
|
||||
|
||||
options.find_each do |option|
|
||||
begin
|
||||
fields_to_show = option.options[:fields_to_show]
|
||||
next if fields_to_show&.exclude?('product')
|
||||
|
||||
fields_to_show.delete('product')
|
||||
fields_to_show << 'item_name'
|
||||
option.update(options: option.options)
|
||||
rescue StandardError => e
|
||||
puts "Failed to revert rendering option with id: #{option.id}"
|
||||
puts "Error: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
14
db/migrate/20241030023153_add_subject_to_semantic_links.rb
Normal file
14
db/migrate/20241030023153_add_subject_to_semantic_links.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# rails g migration AddSubjectToSemanticLinks subject:references{polymorphic}
|
||||
#
|
||||
# We want to add links to Exchanges as well as Variants.
|
||||
# The word subject comes from the triple structure of the Semantic Web:
|
||||
#
|
||||
# Subject predicate object (variant has linke URL)
|
||||
class AddSubjectToSemanticLinks < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
# We allow `null` until we filled the new columns with existing data.
|
||||
add_reference :semantic_links, :subject, polymorphic: true, null: true
|
||||
end
|
||||
end
|
||||
11
db/migrate/20241030025540_copy_subject_on_semantic_links.rb
Normal file
11
db/migrate/20241030025540_copy_subject_on_semantic_links.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CopySubjectOnSemanticLinks < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
execute <<~SQL.squish
|
||||
UPDATE semantic_links SET
|
||||
subject_id = variant_id,
|
||||
subject_type = 'Spree::Variant'
|
||||
SQL
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
class ChangeNullOnSemanticLinks < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
change_column_null :semantic_links, :subject_id, false
|
||||
change_column_null :semantic_links, :subject_type, false
|
||||
|
||||
change_column_null :semantic_links, :variant_id, true
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_10_23_054951) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_10_30_033956) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "plpgsql"
|
||||
@@ -401,10 +401,13 @@ ActiveRecord::Schema[7.0].define(version: 2024_10_23_054951) do
|
||||
end
|
||||
|
||||
create_table "semantic_links", force: :cascade do |t|
|
||||
t.bigint "variant_id", null: false
|
||||
t.bigint "variant_id"
|
||||
t.string "semantic_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "subject_type", null: false
|
||||
t.bigint "subject_id", null: false
|
||||
t.index ["subject_type", "subject_id"], name: "index_semantic_links_on_subject"
|
||||
t.index ["variant_id"], name: "index_semantic_links_on_variant_id"
|
||||
end
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# Docker Scripts
|
||||
|
||||
## What's the point?
|
||||
* Setting up the Open Food Network app on your local machine is quick and easy with the aid of Docker.
|
||||
* Docker provides a common virtual environment available to all developers and resolves the infamous "but it works on my machine" problem.
|
||||
* Use the scripts in this directory to execute tasks in Docker. Please note that these scripts are intended to be executed from this app's root directory (/openfoodnetwork). These scripts allow you to bypass the need to keep typing "docker compose run web".
|
||||
Docker is intended to provide a common virtual environment available to all developers. Please note that it is not commonly used by developers at this time.
|
||||
|
||||
## Limitations
|
||||
1. The docker environment can't directly control your host system browser, which means that browser specs (under `/spec/system/`) and email previews will not work. You may be able to find a solution with [this article](https://evilmartians.com/chronicles/system-of-a-test-setting-up-end-to-end-rails-testing). If so, please contribute!
|
||||
@@ -120,6 +117,8 @@ You may also need to comment out stuff related to Chromedriver and Chrome. Chrom
|
||||
See [#8421](https://github.com/openfoodfoundation/openfoodnetwork/issues/8421) for more info
|
||||
|
||||
## Script Summary
|
||||
Use the scripts in this directory to execute tasks in Docker. Please note that these scripts are intended to be executed from this app's root directory (/openfoodnetwork). These scripts allow you to bypass the need to keep typing "docker compose run web".
|
||||
|
||||
* docker/build(.ps1): This script builds the Docker containers specified for this app, seeds the database, and logs the screen output for these operations. After you use "git clone" to download this repository, run the docker/build script to start the setup process.
|
||||
* docker/server(.ps1): Use this script to run this app in the Rails server. This script executes the "docker compose up" command and logs the results. If all goes well, you will be able to view this app on your local browser at http://localhost:3000/.
|
||||
* docker/test(.ps1): Use this script to run the entire test suite. **Note limitation with system specs mentioned above**.
|
||||
|
||||
@@ -14,8 +14,8 @@ module Reporting
|
||||
customer_phone: proc { |line_item| line_item.order.bill_address.phone },
|
||||
customer_city: proc { |line_item| line_item.order.bill_address.city },
|
||||
sku: proc { |line_item| line_item.product.sku },
|
||||
item_name: proc { |line_item| line_item.product.name },
|
||||
variant: proc { |line_item| line_item.unit_to_display },
|
||||
product: proc { |line_item| line_item.product.name },
|
||||
variant: proc { |line_item| line_item.full_name },
|
||||
quantity: proc { |line_item| line_item.quantity },
|
||||
max_quantity: proc { |line_item| line_item.max_quantity },
|
||||
cost: proc { |line_item| line_item.price * line_item.quantity },
|
||||
|
||||
7
spec/factories/report_rendering_options_factory.rb
Normal file
7
spec/factories/report_rendering_options_factory.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :orders_and_distributors_options, class: ReportRenderingOptions do
|
||||
report_type { "orders_and_distributors" }
|
||||
end
|
||||
end
|
||||
File diff suppressed because one or more lines are too long
@@ -116,13 +116,19 @@ RSpec.describe BackorderJob do
|
||||
|
||||
describe "#place_order" do
|
||||
it "schedules backorder completion for specific enterprises" do
|
||||
order.order_cycle = build(
|
||||
order.order_cycle = create(
|
||||
:simple_order_cycle,
|
||||
id: 1,
|
||||
orders_close_at: Date.tomorrow.noon,
|
||||
)
|
||||
completion_time = Date.tomorrow.noon + 4.hours
|
||||
|
||||
exchange = order.order_cycle.exchanges.create!(
|
||||
incoming: false,
|
||||
sender: order.order_cycle.coordinator,
|
||||
receiver: order.distributor,
|
||||
)
|
||||
|
||||
urls = FdcUrlBuilder.new(product_link)
|
||||
orderer = FdcBackorderer.new(user, urls)
|
||||
backorder = orderer.build_new_order(order)
|
||||
@@ -132,6 +138,7 @@ RSpec.describe BackorderJob do
|
||||
expect {
|
||||
subject.place_order(user, order, orderer, backorder)
|
||||
}.to enqueue_job(CompleteBackorderJob).at(completion_time)
|
||||
.and change { exchange.semantic_links.count }.by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,11 +25,14 @@ RSpec.describe CompleteBackorderJob do
|
||||
chia_line = orderer.find_or_build_order_line(backorder, chia_offer)
|
||||
chia_line.quantity = 5
|
||||
|
||||
orderer.send_order(backorder)
|
||||
orderer.send_order(backorder).tap do |o|
|
||||
exchange.semantic_links.create!(semantic_id: o.semanticId)
|
||||
end
|
||||
}
|
||||
let(:ofn_order) { create(:completed_order_with_totals) }
|
||||
let(:distributor) { ofn_order.distributor }
|
||||
let(:order_cycle) { ofn_order.order_cycle }
|
||||
let(:exchange) { order_cycle.exchanges.outgoing.first }
|
||||
let(:beans) { ofn_order.line_items[0].variant }
|
||||
let(:chia) { chia_item.variant }
|
||||
let(:chia_item) { ofn_order.line_items[1] }
|
||||
@@ -77,6 +80,9 @@ RSpec.describe CompleteBackorderJob do
|
||||
.and change {
|
||||
current_order.lines[1].quantity.to_i
|
||||
}.from(5).to(7)
|
||||
.and change {
|
||||
exchange.semantic_links.count
|
||||
}.by(-1)
|
||||
end
|
||||
|
||||
it "removes line items", vcr: true do
|
||||
@@ -109,5 +115,21 @@ RSpec.describe CompleteBackorderJob do
|
||||
}.to enqueue_mail(BackorderMailer, :backorder_incomplete)
|
||||
.and raise_error VCR::Errors::UnhandledHTTPRequestError
|
||||
end
|
||||
|
||||
it "skips empty backorders" do
|
||||
user = nil
|
||||
distributor = nil
|
||||
order_cycle = nil
|
||||
order_id = nil
|
||||
backorder = DataFoodConsortium::Connector::Order.new(
|
||||
order_id, orderStatus: "dfc-v:Held"
|
||||
)
|
||||
expect_any_instance_of(FdcBackorderer)
|
||||
.to receive(:find_order).and_return(backorder)
|
||||
|
||||
expect {
|
||||
subject.perform(user, distributor, order_cycle, order_id)
|
||||
}.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ RSpec.describe Reporting::Reports::OrdersAndDistributors::Base do
|
||||
[
|
||||
'Order date', 'Order Id',
|
||||
'Customer Name', 'Customer Email', 'Customer Phone', 'Customer City',
|
||||
'SKU', 'Item name', 'Variant', 'Quantity', 'Max Quantity', 'Cost', 'Shipping Cost',
|
||||
'SKU', 'Product', 'Variant', 'Quantity', 'Max Quantity', 'Cost', 'Shipping Cost',
|
||||
'Payment Method',
|
||||
'Distributor', 'Distributor address', 'Distributor city', 'Distributor postcode',
|
||||
'Shipping Method', 'Shipping instructions'
|
||||
@@ -37,7 +37,7 @@ RSpec.describe Reporting::Reports::OrdersAndDistributors::Base do
|
||||
}
|
||||
let(:payment_method) { create(:payment_method, distributors: [distributor]) }
|
||||
let(:payment) { create(:payment, payment_method:, order:) }
|
||||
let(:line_item) { create(:line_item_with_shipment, product:, order:) }
|
||||
let(:line_item) { create(:line_item_with_shipment, variant:, order:) }
|
||||
subject { described_class.new user }
|
||||
|
||||
before do
|
||||
@@ -46,33 +46,35 @@ RSpec.describe Reporting::Reports::OrdersAndDistributors::Base do
|
||||
order.line_items << line_item
|
||||
end
|
||||
|
||||
it 'should denormalise order and distributor details for display as csv' do
|
||||
allow(subject).to receive(:unformatted_render?).and_return(true)
|
||||
table = subject.table_rows
|
||||
context "without variant name" do
|
||||
it 'should denormalise order and distributor details for display as csv' do
|
||||
allow(subject).to receive(:unformatted_render?).and_return(true)
|
||||
table = subject.table_rows
|
||||
|
||||
expect(table.size).to eq 1
|
||||
expect(table[0]).to eq([
|
||||
order.reload.completed_at.strftime("%F %T"),
|
||||
order.id,
|
||||
bill_address.full_name,
|
||||
order.email,
|
||||
bill_address.phone,
|
||||
bill_address.city,
|
||||
line_item.product.sku,
|
||||
line_item.product.name,
|
||||
line_item.unit_to_display,
|
||||
line_item.quantity,
|
||||
line_item.max_quantity,
|
||||
line_item.price * line_item.quantity,
|
||||
line_item.distribution_fee,
|
||||
payment_method.name,
|
||||
distributor.name,
|
||||
distributor.address.address1,
|
||||
distributor.address.city,
|
||||
distributor.address.zipcode,
|
||||
shipping_method.name,
|
||||
shipping_instructions
|
||||
])
|
||||
expect(table.size).to eq 1
|
||||
expect(table[0]).to eq([
|
||||
order.reload.completed_at.strftime("%F %T"),
|
||||
order.id,
|
||||
bill_address.full_name,
|
||||
order.email,
|
||||
bill_address.phone,
|
||||
bill_address.city,
|
||||
line_item.product.sku,
|
||||
line_item.product.name,
|
||||
"1g",
|
||||
line_item.quantity,
|
||||
line_item.max_quantity,
|
||||
line_item.price * line_item.quantity,
|
||||
line_item.distribution_fee,
|
||||
payment_method.name,
|
||||
distributor.name,
|
||||
distributor.address.address1,
|
||||
distributor.address.city,
|
||||
distributor.address.zipcode,
|
||||
shipping_method.name,
|
||||
shipping_instructions
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
it "prints one row per line item" do
|
||||
@@ -149,6 +151,17 @@ RSpec.describe Reporting::Reports::OrdersAndDistributors::Base do
|
||||
"Spree::ShippingMethod Load",
|
||||
]
|
||||
end
|
||||
|
||||
context "with variant name present" do
|
||||
before do
|
||||
variant.update_columns(display_name: 'Variant Name');
|
||||
end
|
||||
let(:row) { subject.table_rows.first }
|
||||
|
||||
it "should display variant name with unit" do
|
||||
expect(row).to include("Variant Name (1g)")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_relative '../../db/migrate/20241011071014_update_item_name_to_product_in_od_report'
|
||||
|
||||
RSpec.describe UpdateItemNameToProductInOdReport, type: :migration do
|
||||
let!(:report_option_without_item_name_product) do
|
||||
create(
|
||||
:orders_and_distributors_options,
|
||||
options: { fields_to_show: ['other_field'] }
|
||||
)
|
||||
end
|
||||
|
||||
describe '#up' do
|
||||
let!(:report_option_with_item_name) do
|
||||
create(
|
||||
:orders_and_distributors_options,
|
||||
options: { fields_to_show: ['item_name', 'other_field'] }
|
||||
)
|
||||
end
|
||||
before { subject.up }
|
||||
|
||||
it 'updates fields_to_show from item_name to product only if options have item_name' do
|
||||
report_option_with_item_name.reload
|
||||
expect(fields_to_show(report_option_with_item_name)).to eq(['other_field', 'product'])
|
||||
expect(fields_to_show(report_option_without_item_name_product)).to eq(['other_field'])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#down' do
|
||||
let!(:report_option_with_product) do
|
||||
create(
|
||||
:orders_and_distributors_options,
|
||||
options: { fields_to_show: ['product', 'other_field'] }
|
||||
)
|
||||
end
|
||||
before { subject.down }
|
||||
|
||||
it 'reverts fields_to_show from product to item_name only if options have product' do
|
||||
report_option_with_product.reload
|
||||
expect(fields_to_show(report_option_with_product)).to eq(['other_field', 'item_name'])
|
||||
expect(fields_to_show(report_option_without_item_name_product)).to eq(['other_field'])
|
||||
end
|
||||
end
|
||||
|
||||
def fields_to_show(report_options)
|
||||
report_options.options[:fields_to_show]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_relative '../../db/migrate/20241030025540_copy_subject_on_semantic_links'
|
||||
|
||||
RSpec.describe CopySubjectOnSemanticLinks do
|
||||
describe "#up" do
|
||||
let(:original_variant) { create(:variant) }
|
||||
let(:dummy_variant) { create(:variant) }
|
||||
|
||||
it "copies the original data" do
|
||||
link = SemanticLink.create!(
|
||||
subject: dummy_variant, # This would be NULL when migration runs.
|
||||
semantic_id: "some-url",
|
||||
)
|
||||
SemanticLink.update_all("variant_id = #{original_variant.id}")
|
||||
|
||||
expect { subject.up }.to change {
|
||||
link.reload.subject
|
||||
}.from(dummy_variant).to(original_variant)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,8 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Exchange do
|
||||
it { is_expected.to have_many :semantic_links }
|
||||
|
||||
it "should be valid when built from factory" do
|
||||
expect(build(:exchange)).to be_valid
|
||||
end
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe SemanticLink, type: :model do
|
||||
it { is_expected.to belong_to :variant }
|
||||
it { is_expected.to belong_to :subject }
|
||||
it { is_expected.to validate_presence_of(:semantic_id) }
|
||||
end
|
||||
|
||||
@@ -6,6 +6,9 @@ RSpec.describe Spree::Order do
|
||||
let(:user) { build(:user, email: "spree@example.com") }
|
||||
let(:order) { build(:order, user:) }
|
||||
|
||||
it { is_expected.to have_one :exchange }
|
||||
it { is_expected.to have_many :semantic_links }
|
||||
|
||||
describe "#errors" do
|
||||
it "provides friendly error messages" do
|
||||
order.ship_address = Spree::Address.new
|
||||
|
||||
@@ -27,7 +27,7 @@ RSpec.describe FdcBackorderer do
|
||||
# After closing the order at the end, the test can be repeated live again.
|
||||
|
||||
# Build a new order when no open one is found:
|
||||
order.order_cycle = build(:order_cycle)
|
||||
order.order_cycle = create(:order_cycle, distributors: [order.distributor])
|
||||
backorder = subject.find_or_build_order(order)
|
||||
expect(backorder.semanticId).to eq urls.orders_url
|
||||
expect(backorder.lines).to eq []
|
||||
@@ -50,10 +50,19 @@ RSpec.describe FdcBackorderer do
|
||||
expect(found_backorder.lines.count).to eq 1
|
||||
expect(found_backorder.lines[0].quantity.to_i).to eq 3
|
||||
|
||||
# Without a stored semantic link, it can't look it up directly though:
|
||||
found_backorder = subject.lookup_open_order(order)
|
||||
expect(found_backorder).to eq nil
|
||||
|
||||
# But with a semantic link, it works:
|
||||
order.exchange.semantic_links.create!(semantic_id: placed_order.semanticId)
|
||||
found_backorder = subject.lookup_open_order(order)
|
||||
expect(found_backorder.semanticId).to eq placed_order.semanticId
|
||||
|
||||
# And close the order again:
|
||||
subject.complete_order(placed_order)
|
||||
remaining_open_order = subject.find_or_build_order(order)
|
||||
expect(remaining_open_order.semanticId).not_to eq placed_order.semanticId
|
||||
expect(remaining_open_order.semanticId).to eq urls.orders_url
|
||||
end
|
||||
|
||||
describe "#find_or_build_order" do
|
||||
|
||||
@@ -27,7 +27,7 @@ RSpec.describe "Orders And Distributors" do
|
||||
context "as an enterprise user" do
|
||||
let(:header) {
|
||||
["Order date", "Order Id", "Customer Name", "Customer Email", "Customer Phone",
|
||||
"Customer City", "SKU", "Item name", "Variant", "Quantity", "Max Quantity",
|
||||
"Customer City", "SKU", "Product", "Variant", "Quantity", "Max Quantity",
|
||||
"Cost", "Shipping Cost", "Payment Method", "Distributor", "Distributor address",
|
||||
"Distributor city", "Distributor postcode", "Shipping Method",
|
||||
"Shipping instructions"]
|
||||
|
||||
Reference in New Issue
Block a user