mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #9212 from jibees/9140-assign-a-customer-to-an-order-in-admin-section
When creating an order, and assigning a customer, fill all the customer inputs in the shipping/billing address form
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
angular.module("admin.orders").directive 'customerSearchOverride', ->
|
||||
restrict: 'C'
|
||||
scope:
|
||||
distributorId: '@'
|
||||
link: (scope, element, attr) ->
|
||||
if $('#customer_autocomplete_template').length > 0
|
||||
customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text())
|
||||
|
||||
formatCustomerResult = (customer) ->
|
||||
customerTemplate
|
||||
customer: customer
|
||||
bill_address: customer.bill_address
|
||||
ship_address: customer.ship_address
|
||||
|
||||
element.select2
|
||||
placeholder: Spree.translations.choose_a_customer
|
||||
minimumInputLength: 3
|
||||
ajax:
|
||||
url: '/admin/search/customers.json'
|
||||
datatype: 'json'
|
||||
data: (term, page) ->
|
||||
{
|
||||
q: term
|
||||
distributor_id: scope.distributorId # modified
|
||||
}
|
||||
results: (data, page) ->
|
||||
{ results: data }
|
||||
dropdownCssClass: 'customer_search'
|
||||
formatResult: formatCustomerResult
|
||||
formatSelection: (customer) ->
|
||||
_.each [
|
||||
'bill_address'
|
||||
'ship_address'
|
||||
], (address) ->
|
||||
data = customer[address]
|
||||
address_parts = [
|
||||
'firstname'
|
||||
'lastname'
|
||||
'company'
|
||||
'address1'
|
||||
'address2'
|
||||
'city'
|
||||
'zipcode'
|
||||
'phone'
|
||||
]
|
||||
attribute_wrapper = '#order_' + address + '_attributes_'
|
||||
if data # modified
|
||||
_.each address_parts, (part) ->
|
||||
$(attribute_wrapper + part).val data[part]
|
||||
return
|
||||
$(attribute_wrapper + 'state_id').select2 'val', data['state_id']
|
||||
$(attribute_wrapper + 'country_id').select2 'val', data['country_id']
|
||||
else
|
||||
_.each address_parts, (part) ->
|
||||
$(attribute_wrapper + part).val ''
|
||||
return
|
||||
$(attribute_wrapper + 'state_id').select2 'val', ''
|
||||
$(attribute_wrapper + 'country_id').select2 'val', ''
|
||||
return
|
||||
$('#order_email').val customer.email
|
||||
$('#user_id').val customer.user_id # modified
|
||||
customer.email
|
||||
@@ -1,19 +0,0 @@
|
||||
<script type='text/template' id='customer_autocomplete_template'>
|
||||
<div class='customer-autocomplete-item'>
|
||||
<div class='customer-details'>
|
||||
<h5>{{customer.email}}</h5>
|
||||
{{#if bill_address.firstname }}
|
||||
<strong>{{t 'bill_address' }}</strong>
|
||||
{{bill_address.firstname}} {{bill_address.lastname}}<br>
|
||||
{{bill_address.address1}}, {{bill_address.address2}}<br>
|
||||
{{bill_address.city}}<br>
|
||||
{{#if bill_address.state_id }}
|
||||
{{bill_address.state.name}}
|
||||
{{else}}
|
||||
{{bill_address.state_name}}
|
||||
{{/if}}
|
||||
{{bill_address.country.name}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
@@ -17,8 +17,8 @@
|
||||
%legend{:align => "center"}= Spree.t(:customer_search)
|
||||
- content_for :main_ng_app_name do
|
||||
= "admin.orders"
|
||||
= hidden_field_tag :customer_search_override, nil, distributor_id: @order.distributor_id, :class => 'fullwidth title customer-search-override'
|
||||
= render :partial => "spree/admin/orders/customer_details/autocomplete", :formats => :js
|
||||
%label{for: "customer_search_override"}= Spree.t(:choose_a_customer)
|
||||
%select{name: "customer_search_override", "data-controller": "select-customer", "data-select-customer-distributor-value": @order.distributor_id, class: "primary", placeholder: Spree.t(:choose_a_customer) }
|
||||
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @order }
|
||||
|
||||
|
||||
50
app/webpacker/controllers/mixins/useRenderCustomer.js
Normal file
50
app/webpacker/controllers/mixins/useRenderCustomer.js
Normal file
@@ -0,0 +1,50 @@
|
||||
export const useRenderCustomer = (controller) => {
|
||||
Object.assign(controller, {
|
||||
renderOption(item, escape) {
|
||||
if (!item.bill_address) {
|
||||
return this.renderWithNoBillAddress(item, escape);
|
||||
}
|
||||
return `<div class='customer-autocomplete-item'>
|
||||
<div class='customer-details'>
|
||||
<h5>${escape(item.email)}</h5>
|
||||
${
|
||||
item.bill_address.firstname
|
||||
? `<strong>${I18n.t("bill_address")}</strong>
|
||||
${item.bill_address.firstname} ${
|
||||
item.bill_address.lastname
|
||||
}<br>
|
||||
${item.bill_address.address1}, ${
|
||||
item.bill_address.address2
|
||||
}<br>
|
||||
${item.bill_address.city}
|
||||
<br>
|
||||
${
|
||||
item.bill_address.state_id &&
|
||||
item.bill_address.state &&
|
||||
item.bill_address.state.name
|
||||
? item.bill_address.state.name
|
||||
: item.bill_address.state_name
|
||||
}
|
||||
|
||||
${
|
||||
item.bill_address.country &&
|
||||
item.bill_address.country.name
|
||||
? item.bill_address.country.name
|
||||
: item.bill_address.country_name
|
||||
}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
renderWithNoBillAddress(item, escape) {
|
||||
return `<div class='customer-autocomplete-item'>
|
||||
<div class='customer-details'><h5>${escape(
|
||||
item.email
|
||||
)}</h5></div>
|
||||
</div>`;
|
||||
},
|
||||
});
|
||||
};
|
||||
22
app/webpacker/controllers/mixins/useSearchCustomer.js
Normal file
22
app/webpacker/controllers/mixins/useSearchCustomer.js
Normal file
@@ -0,0 +1,22 @@
|
||||
export const useSearchCustomer = (controller) => {
|
||||
Object.assign(controller, {
|
||||
load: function (query, callback) {
|
||||
var params = {
|
||||
q: query,
|
||||
distributor_id: this.distributorValue,
|
||||
};
|
||||
|
||||
fetch("/admin/search/customers.json?" + new URLSearchParams(params))
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
this.items = json;
|
||||
callback(json);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.items = [];
|
||||
console.log(error);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
66
app/webpacker/controllers/select_customer_controller.js
Normal file
66
app/webpacker/controllers/select_customer_controller.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import TomSelectController from "./tom_select_controller";
|
||||
import { useSearchCustomer } from "./mixins/useSearchCustomer";
|
||||
import { useRenderCustomer } from "./mixins/useRenderCustomer";
|
||||
|
||||
export default class extends TomSelectController {
|
||||
static values = { options: Object, distributor: Number };
|
||||
|
||||
connect() {
|
||||
useSearchCustomer(this);
|
||||
useRenderCustomer(this);
|
||||
const options = {
|
||||
valueField: "id",
|
||||
labelField: "email",
|
||||
searchField: ["email", "full_name", "last_name"],
|
||||
load: this.load.bind(this),
|
||||
shouldLoad: (query) => query.length > 2,
|
||||
render: {
|
||||
option: this.renderOption.bind(this),
|
||||
},
|
||||
};
|
||||
super.connect(options);
|
||||
this.control.on("item_add", this.onItemSelect.bind(this));
|
||||
this.items = [];
|
||||
}
|
||||
|
||||
onItemSelect(id, item) {
|
||||
const customer = this.items.find((item) => item.id == id);
|
||||
["bill_address", "ship_address"].forEach((address) => {
|
||||
const data = customer[address];
|
||||
const address_parts = [
|
||||
"firstname",
|
||||
"lastname",
|
||||
"address1",
|
||||
"address2",
|
||||
"city",
|
||||
"zipcode",
|
||||
"phone",
|
||||
];
|
||||
const attribute_wrapper = "#order_" + address + "_attributes_";
|
||||
address_parts.forEach((part) => {
|
||||
document.querySelector(attribute_wrapper + part).value = data
|
||||
? data[part]
|
||||
: "";
|
||||
});
|
||||
this.setValueOnTomSelectController(
|
||||
document.querySelector(attribute_wrapper + "state_id"),
|
||||
data ? data.state_id : ""
|
||||
);
|
||||
this.setValueOnTomSelectController(
|
||||
document.querySelector(attribute_wrapper + "country_id"),
|
||||
data ? data.country_id : ""
|
||||
);
|
||||
});
|
||||
$("#order_email").val(customer.email);
|
||||
$("#user_id").val(customer.user_id);
|
||||
}
|
||||
|
||||
setValueOnTomSelectController = (element, value) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
this.application
|
||||
.getControllerForElementAndIdentifier(element, "tom-select")
|
||||
.control.setValue(value, true);
|
||||
};
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
import { Controller } from "stimulus"
|
||||
import TomSelect from "tom-select"
|
||||
import { Controller } from "stimulus";
|
||||
import TomSelect from "tom-select";
|
||||
|
||||
export default class extends Controller {
|
||||
static values = { options: Object }
|
||||
static values = { options: Object };
|
||||
static defaults = {
|
||||
maxItems: 1,
|
||||
maxOptions: null,
|
||||
plugins: ["dropdown_input"],
|
||||
allowEmptyOption: true
|
||||
}
|
||||
allowEmptyOption: true,
|
||||
};
|
||||
|
||||
connect() {
|
||||
this.control = new TomSelect(
|
||||
this.element, { ...this.constructor.defaults, ...this.optionsValue }
|
||||
)
|
||||
connect(options = {}) {
|
||||
this.control = new TomSelect(this.element, {
|
||||
...this.constructor.defaults,
|
||||
...this.optionsValue,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.control) this.control.destroy()
|
||||
if (this.control) this.control.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,12 @@ module WebHelper
|
||||
page.find(:css, 'body').click
|
||||
end
|
||||
|
||||
def tomselect_search_and_select(value, options)
|
||||
page.find("[name='#{options[:from]}']").sibling(".ts-wrapper").click
|
||||
page.find(:css, '.ts-dropdown input.dropdown-input').set(value)
|
||||
page.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click
|
||||
end
|
||||
|
||||
def accept_js_alert
|
||||
page.driver.browser.switch_to.alert.accept
|
||||
end
|
||||
|
||||
@@ -383,7 +383,7 @@ describe '
|
||||
expect(page).to have_selector '#select-customer'
|
||||
|
||||
# And I select that customer's email address and save the order
|
||||
select2_select customer.email, from: 'customer_search_override', search: true
|
||||
tomselect_search_and_select customer.email, from: 'customer_search_override'
|
||||
click_button 'Update'
|
||||
expect(page).to have_selector "h1.js-admin-page-title", text: "Customer Details"
|
||||
|
||||
@@ -391,6 +391,10 @@ describe '
|
||||
order = Spree::Order.last
|
||||
expect(order.ship_address.lastname).to eq customer.ship_address.lastname
|
||||
expect(order.bill_address.lastname).to eq customer.bill_address.lastname
|
||||
expect(order.ship_address.zipcode).to eq customer.ship_address.zipcode
|
||||
expect(order.bill_address.zipcode).to eq customer.bill_address.zipcode
|
||||
expect(order.ship_address.city).to eq customer.ship_address.city
|
||||
expect(order.bill_address.city).to eq customer.bill_address.city
|
||||
end
|
||||
|
||||
context "as an enterprise manager" do
|
||||
|
||||
Reference in New Issue
Block a user