mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Merge pull request #9044 from georgethoppil/optional-restock-items
Optional restock items
This commit is contained in:
@@ -4,6 +4,7 @@ $(document).ready(function() {
|
||||
|
||||
initAlert()
|
||||
initConfirm()
|
||||
initCancelOrder()
|
||||
|
||||
if ($('#variant_autocomplete_template').length > 0) {
|
||||
window.variantTemplate = Handlebars.compile($('#variant_autocomplete_template').text());
|
||||
@@ -52,12 +53,12 @@ $(document).ready(function() {
|
||||
}
|
||||
toggleItemEdit();
|
||||
|
||||
adjustItems(shipment_number, variant_id, quantity);
|
||||
adjustItems(shipment_number, variant_id, quantity, true);
|
||||
return false;
|
||||
}
|
||||
$('a.save-item').click(handle_save_click);
|
||||
|
||||
handle_delete_click = function(elementSelector){
|
||||
handle_delete_click = function(elementSelector, restock_item){
|
||||
var del = $(elementSelector);
|
||||
del.hide()
|
||||
var shipment_number = del.data('shipment-number');
|
||||
@@ -65,26 +66,37 @@ $(document).ready(function() {
|
||||
|
||||
toggleItemEdit();
|
||||
|
||||
adjustItems(shipment_number, variant_id, 0);
|
||||
adjustItems(shipment_number, variant_id, 0, restock_item);
|
||||
}
|
||||
|
||||
$('a.delete-item').click((event) => {
|
||||
ofnConfirm(() => {
|
||||
handle_delete_click('#custom-confirm');
|
||||
});
|
||||
try {
|
||||
var del = $('a.delete-item');
|
||||
var shipment_number = del.data('shipment-number');
|
||||
var variant_id = del.data('variant-id');
|
||||
var shipment = _.findWhere(shipments, {number: shipment_number + ''});
|
||||
var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});
|
||||
if (inventory_units.length !== shipment.inventory_units.length) {
|
||||
ofnConfirm((reStockItem) => {
|
||||
handle_delete_click('#custom-confirm', reStockItem);
|
||||
});
|
||||
} else {
|
||||
adjustItems(shipment_number, variant_id, 0);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
adjustItems = function(shipment_number, variant_id, quantity){
|
||||
adjustItems = function(shipment_number, variant_id, quantity, restock_item){
|
||||
var shipment = _.findWhere(shipments, {number: shipment_number + ''});
|
||||
var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id});
|
||||
|
||||
if (quantity == 0 && inventory_units.length == shipment.inventory_units.length) {
|
||||
ofnCancelOrderAlert((confirm, sendEmailCancellation) => {
|
||||
if (quantity === 0 && inventory_units.length === shipment.inventory_units.length) {
|
||||
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_item) => {
|
||||
if (confirm) {
|
||||
doAdjustItems(shipment_number, variant_id, quantity, inventory_units, () => {
|
||||
doAdjustItems(shipment_number, variant_id, quantity, inventory_units, restock_item, () => {
|
||||
var redirectTo = new URL(Spree.routes.cancel_order.toString());
|
||||
redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation);
|
||||
window.location.href = redirectTo.toString();
|
||||
@@ -93,23 +105,26 @@ adjustItems = function(shipment_number, variant_id, quantity){
|
||||
});
|
||||
return;
|
||||
}
|
||||
doAdjustItems(shipment_number, variant_id, quantity, inventory_units, () => {
|
||||
doAdjustItems(shipment_number, variant_id, quantity, inventory_units, restock_item, () => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
doAdjustItems = function(shipment_number, variant_id, quantity, inventory_units, callback) {
|
||||
doAdjustItems = function(shipment_number, variant_id, quantity, inventory_units, restock_item, callback) {
|
||||
var url = Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number;
|
||||
|
||||
var new_quantity = 0;
|
||||
var data = { variant_id: variant_id };
|
||||
if (inventory_units.length < quantity) {
|
||||
url += "/add";
|
||||
new_quantity = (quantity - inventory_units.length);
|
||||
} else if (inventory_units.length > quantity) {
|
||||
url += "/remove"
|
||||
new_quantity = (inventory_units.length - quantity);
|
||||
data.restock_item = restock_item;
|
||||
}
|
||||
url += '.json';
|
||||
data.quantity = new_quantity;
|
||||
|
||||
if (new_quantity == 0) {
|
||||
ofnAlert(t("js.admin.orders.quantity_unchanged"));
|
||||
@@ -117,7 +132,7 @@ doAdjustItems = function(shipment_number, variant_id, quantity, inventory_units,
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url: Spree.url(url),
|
||||
data: { variant_id: variant_id, quantity: new_quantity }
|
||||
data: data
|
||||
}).done(function( msg ) {
|
||||
callback();
|
||||
});
|
||||
@@ -171,7 +186,7 @@ addVariantFromStockLocation = function() {
|
||||
});
|
||||
}else{
|
||||
//add to existing shipment
|
||||
adjustItems(shipment.number, variant_id, quantity);
|
||||
adjustItems(shipment.number, variant_id, quantity, true);
|
||||
}
|
||||
return 1
|
||||
}
|
||||
@@ -202,11 +217,13 @@ ofnCancelOrderAlert = function(callback, i18nKey) {
|
||||
` ${t(i18nKey)}
|
||||
<div class="form">
|
||||
<input type="checkbox" name="send_cancellation_email" value="1" id="send_cancellation_email" checked="true" />
|
||||
<label for="send_cancellation_email">${t("js.admin.orders.cancel_the_order_send_cancelation_email")}</label>
|
||||
<label for="send_cancellation_email">${t("js.admin.orders.cancel_the_order_send_cancelation_email")}</label><br />
|
||||
<input type="checkbox" name="restock_items" id="restock_items" checked="checked"/>
|
||||
<label for="restock_items">${t("js.admin.orders.restock_items")}</label>
|
||||
</div>`);
|
||||
$('#custom-confirm button.confirm').unbind( "click" ).click(() => {
|
||||
$('#custom-confirm').hide();
|
||||
callback(true, $('#send_cancellation_email').is(':checked'));
|
||||
callback(true, $('#send_cancellation_email').is(':checked'), $('#restock_items').is(':checked'));
|
||||
});
|
||||
$('#custom-confirm button.cancel').click(() => {
|
||||
$('#custom-confirm').hide();
|
||||
@@ -216,7 +233,30 @@ ofnCancelOrderAlert = function(callback, i18nKey) {
|
||||
}
|
||||
|
||||
ofnConfirm = function(callback) {
|
||||
$('#custom-confirm .message').html(
|
||||
` ${t("are_you_sure")}
|
||||
<div class="form">
|
||||
<input type="checkbox" name="restock_items" id="restock_items" checked="checked"/>
|
||||
<label for="restock_items">${t("js.admin.orders.restock_item")}</label>
|
||||
</div>`);
|
||||
$('#custom-confirm').data($(event.target).data());
|
||||
$('#custom-confirm button.confirm').click(callback);
|
||||
$('#custom-confirm button.confirm').click(() => {
|
||||
callback($('#restock_items').is(':checked'));
|
||||
});
|
||||
$('#custom-confirm').show();
|
||||
}
|
||||
|
||||
initCancelOrder = function() {
|
||||
$('#cancel_order_form').submit(function(e){
|
||||
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_items) => {
|
||||
if (confirm) {
|
||||
var redirectTo = new URL(Spree.routes.cancel_order.toString());
|
||||
redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation);
|
||||
redirectTo.searchParams.append("restock_items", restock_items);
|
||||
window.location.href = redirectTo.toString();
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,8 +79,9 @@ module Api
|
||||
def remove
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
restock_item = params.fetch(:restock_item, "true") == "true"
|
||||
|
||||
@order.contents.remove(variant, quantity, @shipment)
|
||||
@order.contents.remove(variant, quantity, @shipment, restock_item)
|
||||
@shipment.reload if @shipment.persisted?
|
||||
|
||||
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
|
||||
|
||||
@@ -66,6 +66,8 @@ module Spree
|
||||
def fire
|
||||
event = params[:e]
|
||||
@order.send_cancellation_email = params[:send_cancellation_email] != "false"
|
||||
@order.restock_items = params.fetch(:restock_items, "true") == "true"
|
||||
|
||||
if @order.public_send(event.to_s)
|
||||
flash[:success] = Spree.t(:order_updated)
|
||||
else
|
||||
|
||||
@@ -115,7 +115,7 @@ module Spree
|
||||
if html_options[:method] &&
|
||||
html_options[:method].to_s.downcase != 'get' &&
|
||||
!html_options[:remote]
|
||||
form_tag(url, method: html_options.delete(:method)) do
|
||||
form_tag(url, method: html_options.delete(:method), id: html_options.delete(:form_id)) do
|
||||
button(text, html_options.delete(:icon), nil, html_options)
|
||||
end
|
||||
else
|
||||
|
||||
@@ -5,8 +5,8 @@ module Spree
|
||||
module OrdersHelper
|
||||
def event_links
|
||||
links = []
|
||||
links << event_link("cancel") if @order.can_cancel?
|
||||
links << event_link("resume") if @order.can_resume?
|
||||
links << cancel_event_link if @order.can_cancel?
|
||||
links << resume_event_link if @order.can_resume?
|
||||
links.join(' ').html_safe
|
||||
end
|
||||
|
||||
@@ -114,12 +114,19 @@ module Spree
|
||||
confirm: t(:are_you_sure) }
|
||||
end
|
||||
|
||||
def event_link(event)
|
||||
event_label = I18n.t(event, scope: "actions")
|
||||
def cancel_event_link
|
||||
event_label = I18n.t("cancel", scope: "actions")
|
||||
button_link_to(event_label,
|
||||
fire_admin_order_url(@order, e: "cancel"),
|
||||
method: :put, icon: "icon-cancel", form_id: "cancel_order_form")
|
||||
end
|
||||
|
||||
def resume_event_link
|
||||
event_label = I18n.t("resume", scope: "actions")
|
||||
confirm_message = I18n.t("admin.orders.edit.order_sure_want_to", event: event_label)
|
||||
button_link_to(event_label,
|
||||
fire_admin_order_url(@order, e: event),
|
||||
method: :put, icon: "icon-#{event}",
|
||||
fire_admin_order_url(@order, e: "resume"),
|
||||
method: :put, icon: "icon-resume",
|
||||
data: { confirm: confirm_message })
|
||||
end
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ module Spree
|
||||
|
||||
attr_accessor :skip_stock_check, :target_shipment # Allows manual skipping of Stock::AvailabilityValidator
|
||||
|
||||
attribute :restock_item, type: :boolean, default: true
|
||||
|
||||
# -- Scopes
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
|
||||
@@ -106,6 +106,7 @@ module Spree
|
||||
after_save_commit DefaultAddressUpdater
|
||||
|
||||
attribute :send_cancellation_email, type: :boolean, default: true
|
||||
attribute :restock_items, type: :boolean, default: true
|
||||
# -- Scopes
|
||||
scope :not_empty, -> {
|
||||
left_outer_joins(:line_items).where.not(spree_line_items: { id: nil })
|
||||
|
||||
@@ -19,8 +19,8 @@ module Spree
|
||||
|
||||
# Get current line item for variant
|
||||
# Remove variant qty from line_item
|
||||
def remove(variant, quantity = nil, shipment = nil)
|
||||
line_item = remove_from_line_item(variant, quantity, shipment)
|
||||
def remove(variant, quantity = nil, shipment = nil, restock_item = true)
|
||||
line_item = remove_from_line_item(variant, quantity, shipment, restock_item)
|
||||
update_shipment(shipment)
|
||||
order.update_order_fees! if order.completed?
|
||||
update_order
|
||||
@@ -97,9 +97,9 @@ module Spree
|
||||
line_item
|
||||
end
|
||||
|
||||
def remove_from_line_item(variant, quantity, shipment = nil)
|
||||
def remove_from_line_item(variant, quantity, shipment = nil, restock_item = true)
|
||||
line_item = find_line_item_by_variant(variant, true)
|
||||
|
||||
line_item.restock_item = restock_item
|
||||
quantity.present? ? line_item.quantity += -quantity : line_item.quantity = 0
|
||||
line_item.target_shipment = shipment
|
||||
|
||||
|
||||
@@ -44,12 +44,15 @@ module Spree
|
||||
quantity = variant_units.size - line_item.quantity
|
||||
|
||||
if shipment.present?
|
||||
remove_from_shipment(shipment, line_item.variant, quantity)
|
||||
remove_from_shipment(shipment, line_item.variant, quantity, line_item.restock_item)
|
||||
else
|
||||
order.shipments.each do |each_shipment|
|
||||
break if quantity == 0
|
||||
|
||||
quantity -= remove_from_shipment(each_shipment, line_item.variant, quantity)
|
||||
quantity -= remove_from_shipment(each_shipment,
|
||||
line_item.variant,
|
||||
quantity,
|
||||
line_item.restock_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -83,7 +86,7 @@ module Spree
|
||||
quantity
|
||||
end
|
||||
|
||||
def remove_from_shipment(shipment, variant, quantity)
|
||||
def remove_from_shipment(shipment, variant, quantity, restock_item)
|
||||
return 0 if quantity == 0 || shipment.shipped?
|
||||
|
||||
shipment_units = shipment.inventory_units_for(variant).reject do |variant_unit|
|
||||
@@ -101,7 +104,7 @@ module Spree
|
||||
shipment.destroy if shipment.inventory_units.reload.count == 0
|
||||
|
||||
# removing this from shipment, and adding to stock_location
|
||||
if order.completed?
|
||||
if order.completed? && restock_item
|
||||
shipment.stock_location.restock variant, removed_quantity, shipment
|
||||
end
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ module Spree
|
||||
end
|
||||
|
||||
def after_cancel
|
||||
manifest.each { |item| manifest_restock(item) }
|
||||
manifest.each { |item| manifest_restock(item) } if order.restock_items
|
||||
end
|
||||
|
||||
def after_resume
|
||||
|
||||
@@ -3083,6 +3083,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
quantity_unchanged: "Quantity unchanged from previous amount."
|
||||
cancel_the_order_html: "This will cancel the current order.<br />Are you sure you want to proceed?"
|
||||
cancel_the_order_send_cancelation_email: "Send a cancellation email to the customer"
|
||||
restock_item: "Restock Items: return this item to stock"
|
||||
restock_items: "Restock Items: return all items to stock"
|
||||
resend_user_email_confirmation:
|
||||
resend: "Resend"
|
||||
sending: "Resend..."
|
||||
|
||||
@@ -153,6 +153,13 @@ describe Api::V0::ShipmentsController, type: :controller do
|
||||
api_put :remove, params.merge(variant_id: existing_variant.to_param)
|
||||
}.to change { existing_variant.reload.on_hand }.by(2)
|
||||
end
|
||||
|
||||
it 'does not adjust stock when removing a variant' do
|
||||
expect {
|
||||
api_put :remove, params.merge(variant_id: existing_variant.to_param,
|
||||
restock_item: 'false')
|
||||
}.to change { existing_variant.reload.on_hand }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "for canceled orders" do
|
||||
|
||||
@@ -89,12 +89,21 @@ describe Spree::OrderInventory do
|
||||
|
||||
it "doesn't restock items" do
|
||||
expect(shipment.stock_location).not_to receive(:restock)
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1)).to eq 1
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, true)).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context "order is completed" do
|
||||
before { allow(order).to receive_messages completed?: true }
|
||||
|
||||
it "doesn't restock items" do
|
||||
expect(shipment.stock_location).not_to receive(:restock)
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, false)).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
it 'should create stock_movement' do
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1)).to eq 1
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, true)).to eq 1
|
||||
|
||||
stock_item = shipment.stock_location.stock_item(variant)
|
||||
movement = stock_item.stock_movements.last
|
||||
@@ -112,7 +121,7 @@ describe Spree::OrderInventory do
|
||||
expect(shipment.inventory_units_for[1]).not_to receive(:destroy)
|
||||
expect(shipment.inventory_units_for[2]).to receive(:destroy)
|
||||
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 2)).to eq 2
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 2, true)).to eq 2
|
||||
end
|
||||
|
||||
it 'should destroy unshipped units first' do
|
||||
@@ -123,7 +132,7 @@ describe Spree::OrderInventory do
|
||||
expect(shipment.inventory_units_for[0]).not_to receive(:destroy)
|
||||
expect(shipment.inventory_units_for[1]).to receive(:destroy)
|
||||
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1)).to eq 1
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, true)).to eq 1
|
||||
end
|
||||
|
||||
it 'only attempts to destroy as many units as are eligible, and return amount destroyed' do
|
||||
@@ -134,14 +143,14 @@ describe Spree::OrderInventory do
|
||||
expect(shipment.inventory_units_for[0]).not_to receive(:destroy)
|
||||
expect(shipment.inventory_units_for[1]).to receive(:destroy)
|
||||
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1)).to eq 1
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, true)).to eq 1
|
||||
end
|
||||
|
||||
it 'should destroy self if not inventory units remain' do
|
||||
allow(shipment.inventory_units).to receive_messages(count: 0)
|
||||
expect(shipment).to receive(:destroy)
|
||||
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1)).to eq 1
|
||||
expect(subject.send(:remove_from_shipment, shipment, variant, 1, true)).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -163,13 +163,9 @@ describe '
|
||||
order.line_items = [order.line_items.first]
|
||||
login_as_admin_and_visit spree.edit_admin_order_path(order)
|
||||
find("a.delete-item").click
|
||||
within(".modal", visible: true) do
|
||||
# ignore first modal by confirming it
|
||||
click_on("OK")
|
||||
end
|
||||
end
|
||||
|
||||
context "it shows a second modal about last item deletion and therefore about order cancellation" do
|
||||
context "it shows a modal about last item deletion and therefore about order cancellation" do
|
||||
it "that the user can close and then nothing change" do
|
||||
expect(page).to have_content "This will cancel the current order."
|
||||
expect(page).to have_checked_field "Send a cancellation email to the customer"
|
||||
@@ -205,23 +201,18 @@ describe '
|
||||
end.to have_enqueued_mail(Spree::OrderMailer, :cancel_email)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "user can cancel an order" do
|
||||
before do
|
||||
login_as_admin_and_visit spree.edit_admin_order_path(order)
|
||||
end
|
||||
|
||||
it "by clicking on the cancel button" do
|
||||
expect do
|
||||
accept_alert do
|
||||
click_button "Cancel"
|
||||
context "that the user can choose to restock item" do
|
||||
let(:shipment) { order.shipments.first }
|
||||
it "uncheck the checkbox to not restock item" do
|
||||
within(".modal", visible: true) do
|
||||
check("restock_items")
|
||||
click_on("OK")
|
||||
end
|
||||
expect(shipment.stock_location).not_to receive(:restock)
|
||||
end
|
||||
end
|
||||
expect(page).to have_content "Order updated"
|
||||
expect(order.reload.state).to eq("canceled")
|
||||
end.to have_enqueued_mail(Spree::OrderMailer, :cancel_email)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user