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:
Filipe
2022-06-13 14:57:31 +01:00
committed by GitHub
9 changed files with 163 additions and 94 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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 }

View 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>`;
},
});
};

View 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();
});
},
});
};

View 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);
};
}

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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