feat: extend SelectionDialog to 11 additional DocTypes
- Add child_doctype, items_field, has_rate, warehouse_field_name, price_list_type, price_list_field constructor options to SelectionDialog - No-rate mode hides price column, price list filter, discount and total in cart (Material Request, Stock Entry, Pick List, Request for Quotation) - Stock Entry uses s_warehouse field; Pick List uses locations child table - Buying documents (Purchase Order/Invoice, Supplier Quotation, Purchase Receipt) now use buying price list filter and buying_price_list field - api.py: add skip_price param to skip price enrichment for no-rate docs - hooks.py: register 11 new doctype JS integrations Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f7e1657f1a
commit
ed8c31e4ad
|
|
@ -11,7 +11,7 @@ from erpnext.stock.get_item_details import get_item_details
|
|||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_items_for_selection(filters=None, start=0, page_length=50, custom_filters=None):
|
||||
def get_items_for_selection(filters=None, start=0, page_length=50, custom_filters=None, skip_price=0):
|
||||
"""
|
||||
Получить список товаров с остатками и ценами для формы подбора
|
||||
|
||||
|
|
@ -33,6 +33,8 @@ def get_items_for_selection(filters=None, start=0, page_length=50, custom_filter
|
|||
if isinstance(custom_filters, str):
|
||||
custom_filters = frappe.parse_json(custom_filters)
|
||||
|
||||
skip_price = flt(skip_price)
|
||||
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
|
|
@ -166,7 +168,7 @@ def get_items_for_selection(filters=None, start=0, page_length=50, custom_filter
|
|||
})
|
||||
|
||||
# Цены
|
||||
if price_list and company:
|
||||
if not skip_price and price_list and company:
|
||||
price_data = get_price_data(
|
||||
item.item_code,
|
||||
warehouse=warehouse,
|
||||
|
|
@ -180,7 +182,7 @@ def get_items_for_selection(filters=None, start=0, page_length=50, custom_filter
|
|||
item_dict.update({
|
||||
'price_list_rate': 0.0,
|
||||
'rate': 0.0,
|
||||
'currency': frappe.defaults.get_global_default('currency') or 'USD'
|
||||
'currency': '' if skip_price else (frappe.defaults.get_global_default('currency') or 'USD')
|
||||
})
|
||||
|
||||
result_items.append(item_dict)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,18 @@ app_include_js = "/assets/selections/js/selection_dialog.js"
|
|||
|
||||
# include js in doctype views
|
||||
doctype_js = {
|
||||
"Sales Invoice": "public/js/sales_invoice.js"
|
||||
"Sales Invoice": "public/js/sales_invoice.js",
|
||||
"Sales Order": "public/js/sales_order.js",
|
||||
"Quotation": "public/js/quotation.js",
|
||||
"Purchase Order": "public/js/purchase_order.js",
|
||||
"Purchase Invoice": "public/js/purchase_invoice.js",
|
||||
"Supplier Quotation": "public/js/supplier_quotation.js",
|
||||
"Request for Quotation": "public/js/request_for_quotation.js",
|
||||
"Delivery Note": "public/js/delivery_note.js",
|
||||
"Purchase Receipt": "public/js/purchase_receipt.js",
|
||||
"Material Request": "public/js/material_request.js",
|
||||
"Stock Entry": "public/js/stock_entry.js",
|
||||
"Pick List": "public/js/pick_list.js",
|
||||
}
|
||||
# doctype_list_js = {"doctype" : "public/js/doctype_list.js"}
|
||||
# doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"}
|
||||
|
|
|
|||
|
|
@ -853,3 +853,11 @@ body.selection-resizing * {
|
|||
.selection-filters::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--text-color);
|
||||
}
|
||||
|
||||
/* No-rate mode: hide price-related elements */
|
||||
.selection-no-rate #selection-pricelist-link,
|
||||
.selection-no-rate label[for="selection-pricelist-link"],
|
||||
.selection-no-rate .cart-item-discount,
|
||||
.selection-no-rate .cart-total,
|
||||
.selection-no-rate .cart-item-price,
|
||||
.selection-no-rate .line-through { display: none !important; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Delivery Note
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Delivery Note', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.customer) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Customer first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Delivery Note',
|
||||
child_doctype: 'Delivery Note Item',
|
||||
has_rate: true
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Material Request
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Material Request', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Material Request',
|
||||
child_doctype: 'Material Request Item',
|
||||
has_rate: false
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Pick List
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Pick List', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.locations.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Pick List',
|
||||
child_doctype: 'Pick List Item',
|
||||
items_field: 'locations',
|
||||
has_rate: false
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Purchase Invoice
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Purchase Invoice', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.supplier) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Supplier first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Purchase Invoice',
|
||||
child_doctype: 'Purchase Invoice Item',
|
||||
has_rate: true,
|
||||
price_list_type: 'buying'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Purchase Order
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Purchase Order', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.supplier) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Supplier first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Purchase Order',
|
||||
child_doctype: 'Purchase Order Item',
|
||||
has_rate: true,
|
||||
price_list_type: 'buying'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Purchase Receipt
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Purchase Receipt', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.supplier) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Supplier first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Purchase Receipt',
|
||||
child_doctype: 'Purchase Receipt Item',
|
||||
has_rate: true,
|
||||
price_list_type: 'buying'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Quotation
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Quotation', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.party_name) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Party first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Quotation',
|
||||
child_doctype: 'Quotation Item',
|
||||
has_rate: true
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Request for Quotation
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Request for Quotation', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Request for Quotation',
|
||||
child_doctype: 'Request for Quotation Item',
|
||||
has_rate: false
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -38,7 +38,8 @@ function setup_selection_button(frm) {
|
|||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Sales Invoice'
|
||||
doctype: 'Sales Invoice',
|
||||
child_doctype: 'Sales Invoice Item'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Sales Order
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Sales Order', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.customer) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Customer first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Sales Order',
|
||||
child_doctype: 'Sales Order Item',
|
||||
has_rate: true
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -6,6 +6,12 @@ class SelectionDialog {
|
|||
constructor(opts) {
|
||||
this.frm = opts.frm;
|
||||
this.doctype = opts.doctype;
|
||||
this.child_doctype = opts.child_doctype;
|
||||
this.items_field = opts.items_field || 'items';
|
||||
this.has_rate = opts.has_rate !== false;
|
||||
this.warehouse_field_name = opts.warehouse_field_name || 'warehouse';
|
||||
this.price_list_type = opts.price_list_type || 'selling';
|
||||
this.price_list_field = opts.price_list_field || (this.price_list_type === 'buying' ? 'buying_price_list' : 'selling_price_list');
|
||||
this.cart = {}; // { item_code: {item_code, item_name, qty, rate, discount_pct, ...} }
|
||||
this.items_data = [];
|
||||
this.current_page = 0;
|
||||
|
|
@ -60,10 +66,10 @@ class SelectionDialog {
|
|||
<label>${__('Warehouse')}</label>
|
||||
<div id="selection-warehouse-link"></div>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
${this.has_rate ? `<div class="filter-group">
|
||||
<label>${__('Price List')}</label>
|
||||
<div id="selection-pricelist-link"></div>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
<div class="filter-group">
|
||||
<div class="selection-stock-toggle">
|
||||
<label class="stock-toggle-label">
|
||||
|
|
@ -179,6 +185,9 @@ class SelectionDialog {
|
|||
|
||||
// Add unique class to modal wrapper for CSS targeting
|
||||
this.dialog.$wrapper.addClass('selection-dialog-wrapper');
|
||||
if (!this.has_rate) {
|
||||
this.dialog.$wrapper.addClass('selection-no-rate');
|
||||
}
|
||||
|
||||
// Force fullscreen with setTimeout to override Frappe's styles
|
||||
setTimeout(() => {
|
||||
|
|
@ -486,13 +495,14 @@ class SelectionDialog {
|
|||
}
|
||||
|
||||
setup_pricelist_field() {
|
||||
if (!this.has_rate) return;
|
||||
const me = this;
|
||||
this.pricelist_field = frappe.ui.form.make_control({
|
||||
df: {
|
||||
fieldtype: 'Link',
|
||||
options: 'Price List',
|
||||
placeholder: __('Select Price List...'),
|
||||
filters: { selling: 1, enabled: 1 },
|
||||
filters: { [me.price_list_type]: 1, enabled: 1 },
|
||||
onchange: function() {
|
||||
me.filters.price_list = this.value || '';
|
||||
me.current_page = 0;
|
||||
|
|
@ -503,7 +513,7 @@ class SelectionDialog {
|
|||
render_input: true,
|
||||
});
|
||||
|
||||
const default_price_list = me.frm.doc.selling_price_list || '';
|
||||
const default_price_list = me.frm.doc[me.price_list_field] || '';
|
||||
if (default_price_list) {
|
||||
me.pricelist_field.set_value(default_price_list);
|
||||
me.filters.price_list = default_price_list;
|
||||
|
|
@ -571,7 +581,7 @@ class SelectionDialog {
|
|||
item_group: this.filters.item_group || '',
|
||||
warehouse: this.filters.warehouse || this.frm.doc.set_warehouse || '',
|
||||
customer: this.frm.doc.customer || '',
|
||||
price_list: this.filters.price_list || this.frm.doc.selling_price_list || '',
|
||||
price_list: this.filters.price_list || this.frm.doc[this.price_list_field] || '',
|
||||
company: this.frm.doc.company || '',
|
||||
transaction_date: this.frm.doc.posting_date || frappe.datetime.get_today(),
|
||||
only_in_stock: this.filters.only_in_stock || false,
|
||||
|
|
@ -597,7 +607,8 @@ class SelectionDialog {
|
|||
page_length: this.page_length,
|
||||
custom_filters: this.custom_filters.filter(cf =>
|
||||
cf.field && (cf.operator === 'is set' || cf.operator === 'is not set' || cf.value !== '')
|
||||
)
|
||||
),
|
||||
skip_price: this.has_rate ? 0 : 1
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
|
|
@ -627,7 +638,7 @@ class SelectionDialog {
|
|||
const columns = [
|
||||
{ key: 'item_name', label: __('Name'), sortable: true },
|
||||
{ key: 'available_qty', label: __('Stock'), sortable: true },
|
||||
{ key: 'rate', label: __('Price'), sortable: true },
|
||||
...(this.has_rate ? [{ key: 'rate', label: __('Price'), sortable: true }] : []),
|
||||
{ key: 'qty_action', label: __('Qty / Add'), sortable: false }
|
||||
];
|
||||
|
||||
|
|
@ -683,9 +694,7 @@ class SelectionDialog {
|
|||
${stock_text} ${item.stock_uom || ''}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<strong>${me.format_currency(item.rate, item.currency)}</strong>
|
||||
</td>
|
||||
${me.has_rate ? `<td><strong>${me.format_currency(item.rate, item.currency)}</strong></td>` : ''}
|
||||
<td class="action-cell">
|
||||
<div class="row-action-group">
|
||||
<input type="text" inputmode="decimal" class="form-control input-sm row-qty-input"
|
||||
|
|
@ -1414,7 +1423,7 @@ class SelectionDialog {
|
|||
}
|
||||
|
||||
cart_array.forEach(item => {
|
||||
const row = frappe.model.add_child(me.frm.doc, 'Sales Invoice Item', 'items');
|
||||
const row = frappe.model.add_child(me.frm.doc, me.child_doctype, me.items_field);
|
||||
row.item_code = item.item_code;
|
||||
row.item_name = item.item_name;
|
||||
row.qty = item.qty;
|
||||
|
|
@ -1422,19 +1431,21 @@ class SelectionDialog {
|
|||
row.uom = item.stock_uom;
|
||||
row.conversion_factor = 1;
|
||||
|
||||
const rate = flt(item.rate || 0);
|
||||
const discount = flt(item.discount_pct || 0);
|
||||
const discounted_rate = discount > 0 ? flt(rate * (1 - discount / 100), 2) : rate;
|
||||
if (me.has_rate) {
|
||||
const rate = flt(item.rate || 0);
|
||||
const discount = flt(item.discount_pct || 0);
|
||||
const discounted_rate = discount > 0 ? flt(rate * (1 - discount / 100), 2) : rate;
|
||||
|
||||
row.price_list_rate = rate;
|
||||
row.discount_percentage = discount > 0 ? discount : 0;
|
||||
row.rate = discounted_rate;
|
||||
row.amount = flt(item.qty * discounted_rate, 2);
|
||||
row.price_list_rate = rate;
|
||||
row.discount_percentage = discount > 0 ? discount : 0;
|
||||
row.rate = discounted_rate;
|
||||
row.amount = flt(item.qty * discounted_rate, 2);
|
||||
}
|
||||
|
||||
if (item.warehouse) row.warehouse = item.warehouse;
|
||||
if (item.warehouse) row[me.warehouse_field_name] = item.warehouse;
|
||||
});
|
||||
|
||||
me.frm.refresh_field('items');
|
||||
me.frm.refresh_field(me.items_field);
|
||||
me.dialog.hide();
|
||||
|
||||
frappe.show_alert({
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Stock Entry
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Stock Entry', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Stock Entry',
|
||||
child_doctype: 'Stock Entry Detail',
|
||||
has_rate: false,
|
||||
warehouse_field_name: 's_warehouse'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Интеграция формы подбора с Supplier Quotation
|
||||
*/
|
||||
|
||||
frappe.ui.form.on('Supplier Quotation', {
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 0) {
|
||||
setup_selection_button(frm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function setup_selection_button(frm) {
|
||||
const grid = frm.fields_dict.items.grid;
|
||||
|
||||
grid.wrapper.find('.grid-add-multiple-rows').remove();
|
||||
|
||||
$('<button type="button" class="grid-add-multiple-rows btn btn-xs btn-secondary">')
|
||||
.html(__('Add Multiple'))
|
||||
.insertAfter(grid.wrapper.find('.grid-add-row'))
|
||||
.on('click', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (!frm.doc.supplier) {
|
||||
frappe.msgprint({
|
||||
title: __('Warning'),
|
||||
message: __('Please select Supplier first'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const selection_dialog = new SelectionDialog({
|
||||
frm: frm,
|
||||
doctype: 'Supplier Quotation',
|
||||
child_doctype: 'Supplier Quotation Item',
|
||||
has_rate: true,
|
||||
price_list_type: 'buying'
|
||||
});
|
||||
selection_dialog.show();
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue