Merge branch 'develop' into issue-9166
This commit is contained in:
commit
690de64734
@ -2,7 +2,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
__version__ = '8.1.3'
|
||||
__version__ = '8.1.6'
|
||||
|
||||
|
||||
def get_default_company(user=None):
|
||||
|
@ -224,9 +224,9 @@ cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
||||
return {
|
||||
filters: [
|
||||
["Account", "account_type", "in", ["Cash", "Bank"]],
|
||||
["Account", "root_type", "=", "Asset"],
|
||||
["Account", "is_group", "=",0],
|
||||
["Account", "company", "=", doc.company]
|
||||
["Account", "company", "=", doc.company],
|
||||
["Account", "report_type", "=", "Balance Sheet"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
3
erpnext/buying/doctype/supplier/regional/india.js
Normal file
3
erpnext/buying/doctype/supplier/regional/india.js
Normal file
@ -0,0 +1,3 @@
|
||||
{% include "erpnext/regional/india/party.js" %}
|
||||
|
||||
erpnext.setup_gst_reminder_button('Supplier');
|
@ -201,6 +201,10 @@ def get_data():
|
||||
{
|
||||
"label": _("Goods and Services Tax (GST India)"),
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "GST Settings",
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "GST HSN Code",
|
||||
|
@ -255,7 +255,7 @@ class BuyingController(StockController):
|
||||
|
||||
def get_items_from_bom(self, item_code, bom):
|
||||
bom_items = frappe.db.sql("""select t2.item_code,
|
||||
t2.qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
|
||||
t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
|
||||
t2.rate, t2.stock_uom, t2.name, t2.description
|
||||
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
|
||||
where t2.parent = t1.name and t1.item = %s
|
||||
|
BIN
erpnext/docs/assets/img/regional/india/gst-settings.png
Normal file
BIN
erpnext/docs/assets/img/regional/india/gst-settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 KiB |
BIN
erpnext/docs/assets/img/regional/india/gstin-portal-update.png
Normal file
BIN
erpnext/docs/assets/img/regional/india/gstin-portal-update.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
BIN
erpnext/docs/assets/img/regional/india/gstin-reminder-email.png
Normal file
BIN
erpnext/docs/assets/img/regional/india/gstin-reminder-email.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
21
erpnext/docs/user/manual/en/regional/india/gst-remimders.md
Normal file
21
erpnext/docs/user/manual/en/regional/india/gst-remimders.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Sending GST Reminders
|
||||
|
||||
You can send email reminders to your Customers and Suppliers so that they can directly add or update their GSTIN numbers
|
||||
|
||||
To send GSTIN Reminders, you can either open the Customer / Supplier record or **GST Settings**
|
||||
|
||||
<img class="screenshot" alt="GST Settings" src="{{docs_base_url}}/assets/img/regional/india/gst-settings.png">
|
||||
|
||||
Here you can click on the "Send GSTIN Update Reminders" button to send email reminders to all your customers
|
||||
|
||||
### Updating GSTIN
|
||||
|
||||
Your customers will receive an email asking them to update their GSTIN and that email will link them to a portal page:
|
||||
|
||||
<img class="screenshot" alt="GST Portal Page" src="{{docs_base_url}}/assets/img/regional/india/gstin-portal-update.png">
|
||||
|
||||
Here they can update their GSTIN and it will automatically be added to your customer GSTIN record.
|
||||
|
||||
#### Sample GSTIN Reminder Email
|
||||
|
||||
<img class="screenshot" alt="GST Reminder Email" src="{{docs_base_url}}/assets/img/regional/india/gstin-reminder-email.png">
|
67
erpnext/docs/user/manual/en/regional/india/gst-setup.md
Normal file
67
erpnext/docs/user/manual/en/regional/india/gst-setup.md
Normal file
@ -0,0 +1,67 @@
|
||||
# GST Features in ERPNext
|
||||
|
||||
### 1. Setting up GSTIN
|
||||
|
||||
GST Law requires that you maintain the GSTIN number for all your suppliers and vendors. In ERPNext, GSTIN is linked to the **Address**
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gstin-customer.gif">
|
||||
|
||||
**GST for your Company Address**
|
||||
|
||||
You also need to set the Address for your own Company and your Company's GST Number
|
||||
|
||||
Go to the Company master and add the GSTIN to your default address.
|
||||
|
||||
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
|
||||
|
||||
### 2. Setting up HSN Codes
|
||||
|
||||
According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
|
||||
|
||||
<img class="screenshot" alt="HSN in Item" src="{{docs_base_url}}/assets/img/regional/india/hsn-item.gif">
|
||||
|
||||
### 3. Making Tax Masters
|
||||
|
||||
To setup Billing in GST, you need to create 3 Tax Accounts for the various GST reporting heads CGST - Central GST, SGST - State GST, IGST - Inter-state GST
|
||||
|
||||
Go to your **Chart of Accounts**, under the Duties and Taxes head of your account, create 3 Accounts
|
||||
|
||||
**Note:** Usually the rate in CGST and SGST is half of IGST. For example if most of your items are billed at 18%, then create IGST at 18%, CGST and SGST at 9% each.
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-in-coa.png">
|
||||
|
||||
### 4. Make Tax Templates
|
||||
|
||||
You will have have to make two tax templates for both your sales and purchase, one for in state sales and other for out of state sales.
|
||||
|
||||
In your **In State GST** template, select 2 accounts, SGST and CGST
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-template-in-state.png">
|
||||
|
||||
In your **Out of State GST** template, select IGST
|
||||
|
||||
### 5. Making GST Ready Invoices
|
||||
|
||||
If you have setup the GSTIN of your Customers and Suppliers, and your tax template, you are ready to go for making GST Ready Invoices!
|
||||
|
||||
For **Sales Invoice**,
|
||||
|
||||
1. Select the correct Customer and Item and the address where the transaction will happen.
|
||||
2. Check if the GSTIN of your Company and Supplier have been correctly set.
|
||||
3. Check if the HSN Number has been set in the Item
|
||||
4. Select the the **In State GST** or **Out of State GST** template that you have created based on the type of transaction
|
||||
5. Save and Submit the Invoice
|
||||
|
||||
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
|
||||
|
||||
### Reports
|
||||
|
||||
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
|
||||
|
||||
<img class="screenshot" alt="GST Menus" src="{{docs_base_url}}/assets/img/regional/india/gst-menu.png">
|
||||
|
||||
You can check the impact of your invoice in the **GST Sales Register** and **GST Itemised Sales Register**
|
||||
|
||||
<img class="screenshot" alt="GST Itemised Sales Register" src="{{docs_base_url}}/assets/img/regional/india/gst-itemised.png">
|
||||
|
||||
|
@ -2,70 +2,4 @@
|
||||
|
||||
As of 2017, India will fall under the new GST (Goods and Services Tax) regime and ERPNext makes it easy for users to track the details of its Supplier and Customers across Invoices and make the required reports.
|
||||
|
||||
## GST Features in ERPNext
|
||||
|
||||
### 1. Setting up GSTIN
|
||||
|
||||
GST Law requires that you maintain the GSTIN number for all your suppliers and vendors. In ERPNext, GSTIN is linked to the **Address**
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gstin-customer.gif">
|
||||
|
||||
**GST for your Company Address**
|
||||
|
||||
You also need to set the Address for your own Company and your Company's GST Number
|
||||
|
||||
Go to the Company master and add the GSTIN to your default address.
|
||||
|
||||
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
|
||||
|
||||
### 2. Setting up HSN Codes
|
||||
|
||||
According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
|
||||
|
||||
<img class="screenshot" alt="HSN in Item" src="{{docs_base_url}}/assets/img/regional/india/hsn-item.gif">
|
||||
|
||||
### 3. Making Tax Masters
|
||||
|
||||
To setup Billing in GST, you need to create 3 Tax Accounts for the various GST reporting heads CGST - Central GST, SGST - State GST, IGST - Inter-state GST
|
||||
|
||||
Go to your **Chart of Accounts**, under the Duties and Taxes head of your account, create 3 Accounts
|
||||
|
||||
**Note:** Usually the rate in CGST and SGST is half of IGST. For example if most of your items are billed at 18%, then create IGST at 18%, CGST and SGST at 9% each.
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-in-coa.png">
|
||||
|
||||
### 4. Make Tax Templates
|
||||
|
||||
You will have have to make two tax templates for both your sales and purchase, one for in state sales and other for out of state sales.
|
||||
|
||||
In your **In State GST** template, select 2 accounts, SGST and CGST
|
||||
|
||||
<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-template-in-state.png">
|
||||
|
||||
In your **Out of State GST** template, select IGST
|
||||
|
||||
### 5. Making GST Ready Invoices
|
||||
|
||||
If you have setup the GSTIN of your Customers and Suppliers, and your tax template, you are ready to go for making GST Ready Invoices!
|
||||
|
||||
For **Sales Invoice**,
|
||||
|
||||
1. Select the correct Customer and Item and the address where the transaction will happen.
|
||||
2. Check if the GSTIN of your Company and Supplier have been correctly set.
|
||||
3. Check if the HSN Number has been set in the Item
|
||||
4. Select the the **In State GST** or **Out of State GST** template that you have created based on the type of transaction
|
||||
5. Save and Submit the Invoice
|
||||
|
||||
<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
|
||||
|
||||
### Reports
|
||||
|
||||
ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
|
||||
|
||||
<img class="screenshot" alt="GST Menus" src="{{docs_base_url}}/assets/img/regional/india/gst-menu.png">
|
||||
|
||||
You can check the impact of your invoice in the **GST Sales Register** and **GST Itemised Sales Register**
|
||||
|
||||
<img class="screenshot" alt="GST Itemised Sales Register" src="{{docs_base_url}}/assets/img/regional/india/gst-itemised.png">
|
||||
|
||||
|
||||
{index}
|
2
erpnext/docs/user/manual/en/regional/india/index.txt
Normal file
2
erpnext/docs/user/manual/en/regional/india/index.txt
Normal file
@ -0,0 +1,2 @@
|
||||
gst-setup
|
||||
gst-reminders
|
@ -5,7 +5,7 @@ frappe.provide("erpnext.bom");
|
||||
|
||||
frappe.ui.form.on("BOM", {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch('buying_price_list', 'currency', 'currency')
|
||||
frm.add_fetch('buying_price_list', 'currency', 'currency');
|
||||
frm.fields_dict["items"].grid.get_field("bom_no").get_query = function(doc, cdt, cdn){
|
||||
return {
|
||||
filters: {'currency': frm.doc.currency}
|
||||
@ -74,6 +74,15 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
|
||||
|
||||
get_bom_material_detail(doc, cdt, cdn, scrap_items);
|
||||
},
|
||||
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
|
||||
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
|
||||
item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
|
||||
refresh_field("stock_qty", item.name, item.parentfield);
|
||||
this.toggle_conversion_factor(item);
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
|
||||
@ -300,6 +309,13 @@ frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) {
|
||||
})
|
||||
});
|
||||
|
||||
frappe.ui.form.on("BOM Item", "qty", function(frm, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
d.stock_qty = d.qty * d.conversion_factor;
|
||||
refresh_field("items");
|
||||
});
|
||||
|
||||
|
||||
frappe.ui.form.on("BOM Operation", "operations_remove", function(frm) {
|
||||
erpnext.bom.calculate_op_cost(frm.doc);
|
||||
erpnext.bom.calculate_total(frm.doc);
|
||||
|
@ -7,6 +7,7 @@ from frappe.utils import cint, cstr, flt
|
||||
from frappe import _
|
||||
from erpnext.setup.utils import get_exchange_rate
|
||||
from frappe.website.website_generator import WebsiteGenerator
|
||||
from erpnext.stock.get_item_details import get_conversion_factor
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
@ -48,7 +49,7 @@ class BOM(WebsiteGenerator):
|
||||
self.set_conversion_rate()
|
||||
|
||||
from erpnext.utilities.transaction_base import validate_uom_is_integer
|
||||
validate_uom_is_integer(self, "stock_uom", "qty", "BOM Item")
|
||||
validate_uom_is_integer(self, "stock_uom", "stock_qty", "BOM Item")
|
||||
|
||||
self.validate_materials()
|
||||
self.set_bom_material_details()
|
||||
@ -60,6 +61,7 @@ class BOM(WebsiteGenerator):
|
||||
|
||||
def on_update(self):
|
||||
self.check_recursion()
|
||||
self.update_stock_qty()
|
||||
self.update_exploded_items()
|
||||
|
||||
def on_submit(self):
|
||||
@ -94,7 +96,7 @@ class BOM(WebsiteGenerator):
|
||||
def set_bom_material_details(self):
|
||||
for item in self.get("items"):
|
||||
ret = self.get_bom_material_detail({"item_code": item.item_code, "item_name": item.item_name, "bom_no": item.bom_no,
|
||||
"qty": item.qty})
|
||||
"stock_qty": item.stock_qty})
|
||||
for r in ret:
|
||||
if not item.get(r):
|
||||
item.set(r, ret[r])
|
||||
@ -122,8 +124,11 @@ class BOM(WebsiteGenerator):
|
||||
'description' : item and args['description'] or '',
|
||||
'image' : item and args['image'] or '',
|
||||
'stock_uom' : item and args['stock_uom'] or '',
|
||||
'uom' : item and args['stock_uom'] or '',
|
||||
'conversion_factor' : 1,
|
||||
'bom_no' : args['bom_no'],
|
||||
'rate' : rate,
|
||||
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
|
||||
'base_rate' : rate if self.company_currency() == self.currency else rate * self.conversion_rate
|
||||
}
|
||||
return ret_item
|
||||
@ -160,7 +165,7 @@ class BOM(WebsiteGenerator):
|
||||
|
||||
for d in self.get("items"):
|
||||
rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no,
|
||||
'qty': d.qty})["rate"]
|
||||
'stock_qty': d.stock_qty})["rate"]
|
||||
if rate:
|
||||
d.rate = rate
|
||||
|
||||
@ -240,6 +245,19 @@ class BOM(WebsiteGenerator):
|
||||
frappe.db.get_value('Price List', self.buying_price_list, 'currency') != self.currency:
|
||||
frappe.throw(_("Currency of the price list {0} is not similar with the selected currency {1}").format(self.buying_price_list, self.currency))
|
||||
|
||||
|
||||
def update_stock_qty(self):
|
||||
for m in self.get('items'):
|
||||
|
||||
if not m.conversion_factor:
|
||||
m.conversion_factor = flt(get_conversion_factor(m.item_code, m.uom)['conversion_factor'])
|
||||
if m.uom and m.qty:
|
||||
m.stock_qty = flt(m.conversion_factor)*flt(m.qty)
|
||||
if not m.uom and m.stock_uom:
|
||||
m.uom = m.stock_uom
|
||||
m.qty = m.stock_qty
|
||||
|
||||
|
||||
def set_conversion_rate(self):
|
||||
self.conversion_rate = get_exchange_rate(self.currency, self.company_currency())
|
||||
|
||||
@ -259,7 +277,7 @@ class BOM(WebsiteGenerator):
|
||||
for m in self.get('items'):
|
||||
if m.bom_no:
|
||||
validate_bom_no(m.item_code, m.bom_no)
|
||||
if flt(m.qty) <= 0:
|
||||
if flt(m.stock_qty) <= 0:
|
||||
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
|
||||
check_list.append(m)
|
||||
|
||||
@ -351,9 +369,9 @@ class BOM(WebsiteGenerator):
|
||||
d.rate = self.get_bom_unitcost(d.bom_no)
|
||||
|
||||
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
|
||||
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
|
||||
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
|
||||
d.base_amount = d.amount * flt(self.conversion_rate)
|
||||
d.qty_consumed_per_unit = flt(d.qty, self.precision("qty", d)) / flt(self.quantity, self.precision("quantity"))
|
||||
d.qty_consumed_per_unit = flt(d.stock_qty, self.precision("stock_qty", d)) / flt(self.quantity, self.precision("quantity"))
|
||||
total_rm_cost += d.amount
|
||||
base_total_rm_cost += d.base_amount
|
||||
|
||||
@ -367,7 +385,7 @@ class BOM(WebsiteGenerator):
|
||||
|
||||
for d in self.get('scrap_items'):
|
||||
d.base_rate = d.rate * self.conversion_rate
|
||||
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
|
||||
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
|
||||
d.base_amount = d.amount * self.conversion_rate
|
||||
total_sm_cost += d.amount
|
||||
base_total_sm_cost += d.base_amount
|
||||
@ -385,7 +403,7 @@ class BOM(WebsiteGenerator):
|
||||
self.cur_exploded_items = {}
|
||||
for d in self.get('items'):
|
||||
if d.bom_no:
|
||||
self.get_child_exploded_items(d.bom_no, d.qty)
|
||||
self.get_child_exploded_items(d.bom_no, d.stock_qty)
|
||||
else:
|
||||
self.add_to_cur_exploded_items(frappe._dict({
|
||||
'item_code' : d.item_code,
|
||||
@ -393,7 +411,7 @@ class BOM(WebsiteGenerator):
|
||||
'description' : d.description,
|
||||
'image' : d.image,
|
||||
'stock_uom' : d.stock_uom,
|
||||
'qty' : flt(d.qty),
|
||||
'stock_qty' : flt(d.stock_qty),
|
||||
'rate' : d.base_rate,
|
||||
}))
|
||||
|
||||
@ -402,16 +420,16 @@ class BOM(WebsiteGenerator):
|
||||
|
||||
def add_to_cur_exploded_items(self, args):
|
||||
if self.cur_exploded_items.get(args.item_code):
|
||||
self.cur_exploded_items[args.item_code]["qty"] += args.qty
|
||||
self.cur_exploded_items[args.item_code]["stock_qty"] += args.stock_qty
|
||||
else:
|
||||
self.cur_exploded_items[args.item_code] = args
|
||||
|
||||
def get_child_exploded_items(self, bom_no, qty):
|
||||
def get_child_exploded_items(self, bom_no, stock_qty):
|
||||
""" Add all items from Flat BOM of child BOM"""
|
||||
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
|
||||
child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name, bom_item.description,
|
||||
bom_item.stock_uom, bom_item.qty, bom_item.rate,
|
||||
bom_item.qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
|
||||
bom_item.stock_uom, bom_item.stock_qty, bom_item.rate,
|
||||
bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
|
||||
from `tabBOM Explosion Item` bom_item, tabBOM bom
|
||||
where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
|
||||
|
||||
@ -421,7 +439,7 @@ class BOM(WebsiteGenerator):
|
||||
'item_name' : d['item_name'],
|
||||
'description' : d['description'],
|
||||
'stock_uom' : d['stock_uom'],
|
||||
'qty' : d['qty_consumed_per_unit']*qty,
|
||||
'stock_qty' : d['qty_consumed_per_unit']*stock_qty,
|
||||
'rate' : flt(d['rate']),
|
||||
}))
|
||||
|
||||
@ -433,8 +451,8 @@ class BOM(WebsiteGenerator):
|
||||
ch = self.append('exploded_items', {})
|
||||
for i in self.cur_exploded_items[d].keys():
|
||||
ch.set(i, self.cur_exploded_items[d][i])
|
||||
ch.amount = flt(ch.qty) * flt(ch.rate)
|
||||
ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.quantity)
|
||||
ch.amount = flt(ch.stock_qty) * flt(ch.rate)
|
||||
ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
|
||||
ch.docstatus = self.docstatus
|
||||
ch.db_insert()
|
||||
|
||||
@ -468,7 +486,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
||||
query = """select
|
||||
bom_item.item_code,
|
||||
item.item_name,
|
||||
sum(bom_item.qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
||||
sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
|
||||
item.description,
|
||||
item.image,
|
||||
item.stock_uom,
|
||||
@ -478,13 +496,13 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
|
||||
from
|
||||
`tab{table}` bom_item, `tabBOM` bom, `tabItem` item
|
||||
where
|
||||
bom_item.parent = bom.name
|
||||
and bom_item.docstatus < 2
|
||||
and bom_item.parent = %(bom)s
|
||||
bom_item.docstatus < 2
|
||||
and bom.name = %(bom)s
|
||||
and bom_item.parent = bom.name
|
||||
and item.name = bom_item.item_code
|
||||
and is_stock_item = 1
|
||||
{conditions}
|
||||
group by item_code, stock_uom"""
|
||||
group by item_code, stock_uom"""
|
||||
|
||||
if fetch_exploded:
|
||||
query = query.format(table="BOM Explosion Item",
|
||||
@ -536,7 +554,7 @@ def get_children():
|
||||
return frappe.db.sql("""select
|
||||
bom_item.item_code,
|
||||
bom_item.bom_no as value,
|
||||
bom_item.qty,
|
||||
bom_item.stock_qty,
|
||||
if(ifnull(bom_item.bom_no, "")!="", 1, 0) as expandable,
|
||||
item.image,
|
||||
item.description
|
||||
|
@ -6,7 +6,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Serialized Item With Series",
|
||||
"parentfield": "items",
|
||||
"qty": 1.0,
|
||||
"stock_qty": 1.0,
|
||||
"rate": 5000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
},
|
||||
@ -15,7 +15,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item 2",
|
||||
"parentfield": "items",
|
||||
"qty": 2.0,
|
||||
"stock_qty": 2.0,
|
||||
"rate": 1000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
}
|
||||
@ -35,7 +35,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"parentfield": "items",
|
||||
"qty": 1.0,
|
||||
"stock_qty": 1.0,
|
||||
"rate": 2000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
}
|
||||
@ -46,7 +46,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item",
|
||||
"parentfield": "items",
|
||||
"qty": 1.0,
|
||||
"stock_qty": 1.0,
|
||||
"rate": 5000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
},
|
||||
@ -55,7 +55,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"parentfield": "items",
|
||||
"qty": 2.0,
|
||||
"stock_qty": 2.0,
|
||||
"rate": 1000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
}
|
||||
@ -84,7 +84,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item",
|
||||
"parentfield": "items",
|
||||
"qty": 1.0,
|
||||
"stock_qty": 1.0,
|
||||
"rate": 5000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
},
|
||||
@ -94,7 +94,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item Home Desktop Manufactured",
|
||||
"parentfield": "items",
|
||||
"qty": 3.0,
|
||||
"stock_qty": 3.0,
|
||||
"rate": 1000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
}
|
||||
@ -124,7 +124,7 @@
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item",
|
||||
"parentfield": "items",
|
||||
"qty": 2.0,
|
||||
"stock_qty": 2.0,
|
||||
"rate": 3000.0,
|
||||
"stock_uom": "_Test UOM"
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "hash",
|
||||
@ -13,6 +14,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -44,6 +46,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -72,6 +75,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -101,6 +105,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -129,6 +134,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -161,6 +167,7 @@
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -189,6 +196,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -218,6 +226,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -248,6 +257,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -276,11 +286,12 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "qty",
|
||||
"fieldname": "stock_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@ -289,7 +300,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Qty",
|
||||
"label": "Stock Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "qty",
|
||||
@ -306,6 +317,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -337,6 +349,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -365,6 +378,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -393,6 +407,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -424,6 +439,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -455,17 +471,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 17:27:43.757983",
|
||||
"modified": "2017-06-02 19:29:34.498719",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Explosion Item",
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@ -11,6 +12,7 @@
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -20,7 +22,8 @@
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
@ -41,6 +44,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -51,6 +55,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Name",
|
||||
@ -69,6 +74,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -79,6 +85,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
@ -96,6 +103,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -105,7 +113,8 @@
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 1,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "BOM No",
|
||||
@ -128,6 +137,7 @@
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -138,6 +148,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
@ -155,6 +166,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -165,6 +177,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Description",
|
||||
@ -186,6 +199,7 @@
|
||||
"width": "250px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -196,6 +210,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
@ -212,6 +227,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -222,6 +238,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image",
|
||||
@ -240,6 +257,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -250,6 +268,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image View",
|
||||
@ -269,6 +288,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -279,6 +299,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Quantity and Rate",
|
||||
@ -296,6 +317,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -306,6 +328,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Qty",
|
||||
@ -319,16 +342,170 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 1,
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "stock_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Stock Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "stock_qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"columns": 0,
|
||||
"fieldname": "conversion_factor",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Conversion Factor",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "stock_uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Stock UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "stock_uom",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "See \"Rate Of Materials Based On\" in Costing Section",
|
||||
"fieldname": "rate",
|
||||
"fieldtype": "Currency",
|
||||
@ -336,7 +513,8 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Rate",
|
||||
"length": 0,
|
||||
@ -354,6 +532,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -364,6 +543,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount",
|
||||
@ -386,62 +566,7 @@
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "stock_uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Stock UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "stock_uom",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -452,6 +577,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Basic Rate (Company Currency)",
|
||||
@ -471,6 +597,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -481,6 +608,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount (Company Currency)",
|
||||
@ -500,6 +628,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -510,6 +639,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
@ -527,6 +657,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -537,6 +668,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Scrap %",
|
||||
@ -556,6 +688,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -566,6 +699,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Qty Consumed Per Unit",
|
||||
@ -585,18 +719,18 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-12-20 12:54:34.859076",
|
||||
"modified_by": "rmehta@gmail.com",
|
||||
"modified": "2017-05-23 15:59:37.946963",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Item",
|
||||
"owner": "Administrator",
|
||||
@ -604,7 +738,9 @@
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
@ -33,7 +33,7 @@ class BOMReplaceTool(Document):
|
||||
from `tabBOM` where name = %s""", self.current_bom)
|
||||
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
|
||||
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
|
||||
rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
|
||||
rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2""",
|
||||
(self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom))
|
||||
|
||||
def get_parent_boms(self):
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@ -11,6 +12,7 @@
|
||||
"editable_grid": 1,
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -21,7 +23,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -31,6 +35,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@ -38,6 +43,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -48,7 +54,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -57,6 +65,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -64,6 +73,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -74,7 +84,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Quantity and Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -83,6 +95,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -90,17 +103,20 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "qty",
|
||||
"fieldname": "stock_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -109,6 +125,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@ -116,6 +133,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -126,7 +144,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -136,6 +156,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -143,6 +164,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -153,7 +175,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -163,6 +187,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -170,6 +195,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -180,7 +206,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@ -188,6 +216,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -195,6 +224,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -205,7 +235,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Stock UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -215,6 +247,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -222,6 +255,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -232,7 +266,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Basic Rate (Company Currency)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -242,6 +278,7 @@
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -249,6 +286,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@ -259,7 +297,9 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Basic Amount (Company Currency)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -269,6 +309,7 @@
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -276,17 +317,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-10-25 00:27:53.712140",
|
||||
"modified": "2017-05-23 16:04:32.442287",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Scrap Item",
|
||||
@ -296,7 +337,9 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -266,9 +266,9 @@ class TestProductionOrder(unittest.TestCase):
|
||||
|
||||
def get_scrap_item_details(bom_no):
|
||||
scrap_items = {}
|
||||
for item in frappe.db.sql("""select item_code, qty from `tabBOM Scrap Item`
|
||||
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
|
||||
where parent = %s""", bom_no, as_dict=1):
|
||||
scrap_items[item.item_code] = item.qty
|
||||
scrap_items[item.item_code] = item.stock_qty
|
||||
|
||||
return scrap_items
|
||||
|
||||
@ -287,8 +287,7 @@ def make_prod_order_test_record(**args):
|
||||
pro_order.stock_uom = args.stock_uom or "_Test UOM"
|
||||
pro_order.use_multi_level_bom=0
|
||||
pro_order.set_production_order_operations()
|
||||
|
||||
|
||||
|
||||
if args.source_warehouse:
|
||||
pro_order.source_warehouse = args.source_warehouse
|
||||
|
||||
@ -297,6 +296,7 @@ def make_prod_order_test_record(**args):
|
||||
|
||||
if not args.do_not_save:
|
||||
pro_order.insert()
|
||||
|
||||
if not args.do_not_submit:
|
||||
pro_order.submit()
|
||||
return pro_order
|
||||
|
@ -321,7 +321,7 @@ class ProductionPlanningTool(Document):
|
||||
# get all raw materials with sub assembly childs
|
||||
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
|
||||
for d in frappe.db.sql("""select fb.item_code,
|
||||
ifnull(sum(fb.qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
ifnull(sum(fb.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
fb.description, fb.stock_uom, item.min_order_qty
|
||||
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` item
|
||||
where bom.name = fb.parent and item.name = fb.item_code
|
||||
@ -348,7 +348,7 @@ class ProductionPlanningTool(Document):
|
||||
SELECT
|
||||
bom_item.item_code,
|
||||
default_material_request_type,
|
||||
ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
item.is_sub_contracted_item as is_sub_contracted,
|
||||
item.default_bom as default_bom,
|
||||
bom_item.description as description,
|
||||
|
@ -235,9 +235,9 @@ def create_test_records():
|
||||
"is_active": 1,
|
||||
"is_default": 1,
|
||||
"docstatus": 1,
|
||||
"with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "qty":1,
|
||||
"with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "stock_qty":1,
|
||||
"rate":100, "amount": 100, "stock_uom": "_Test UOM"},
|
||||
{"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "qty":4, "rate":100,
|
||||
{"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "stock_qty":4, "rate":100,
|
||||
"amount": 400,"stock_uom": "_Test UOM"}])
|
||||
|
||||
bom_subC = make_bom("BOM-_Test PPT Item Sub C-001",{"quantity":1,
|
||||
@ -247,9 +247,9 @@ def create_test_records():
|
||||
"docstatus": 1,
|
||||
"with_operations": 0}, [
|
||||
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
|
||||
"doctype":"BOM Item", "qty":6, "rate":100, "amount": 600},
|
||||
"doctype":"BOM Item", "stock_qty":6, "rate":100, "amount": 600},
|
||||
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
|
||||
"bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "qty":2,
|
||||
"bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "stock_qty":2,
|
||||
"rate":100, "amount": 200}])
|
||||
|
||||
bom_sCA = make_bom("BOM-_Test PPT Item SC A-001",{"quantity":1,
|
||||
@ -259,7 +259,7 @@ def create_test_records():
|
||||
"docstatus": 1,
|
||||
"with_operations": 0}, [
|
||||
{"item_code": "_Test PPT Item Raw D","item_name": "_Test PPT Item Raw D",
|
||||
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}])
|
||||
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}])
|
||||
|
||||
bom_sCB = make_bom("BOM-_Test PPT Item SC B-001",{"quantity":1,
|
||||
"item": "_Test PPT Item SC B",
|
||||
@ -268,9 +268,9 @@ def create_test_records():
|
||||
"docstatus": 1,
|
||||
"with_operations": 0}, [
|
||||
{"item_code": "_Test PPT Item Raw B","item_name": "_Test PPT Item Raw B",
|
||||
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
|
||||
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
|
||||
{"item_code": "_Test PPT Item Raw C","item_name": "_Test PPT Item Raw C",
|
||||
"doctype":"BOM Item", "qty":4, "rate":100, "amount": 400}])
|
||||
"doctype":"BOM Item", "stock_qty":4, "rate":100, "amount": 400}])
|
||||
|
||||
bom_subA = make_bom("BOM-_Test PPT Item Sub A-001",{"quantity":1,
|
||||
"item": "_Test PPT Item Sub A",
|
||||
@ -278,11 +278,11 @@ def create_test_records():
|
||||
"is_default": 1,
|
||||
"docstatus": 1,
|
||||
"with_operations": 0}, [
|
||||
{"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
|
||||
{"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
|
||||
"bom_no":"BOM-_Test PPT Item Sub C-001", "doctype":"BOM Item",
|
||||
"qty":1, "rate":100, "amount": 100},
|
||||
"stock_qty":1, "rate":100, "amount": 100},
|
||||
{"item_code": "_Test PPT Item SC B","item_name": "_Test PPT Item SC B",
|
||||
"bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "qty":2,
|
||||
"bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "stock_qty":2,
|
||||
"rate":100, "amount": 200}])
|
||||
|
||||
bom_master = make_bom("BOM-_Test PPT Item Master-001",{"quantity":1,
|
||||
@ -293,16 +293,16 @@ def create_test_records():
|
||||
"with_operations": 0}, [
|
||||
{"item_code": "_Test PPT Item Sub A","item_name": "_Test PPT Item Sub A",
|
||||
"bom_no":"BOM-_Test PPT Item Sub A-001",
|
||||
"doctype":"BOM Item", "qty":2, "rate":100, "amount": 200},
|
||||
"doctype":"BOM Item", "stock_qty":2, "rate":100, "amount": 200},
|
||||
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
|
||||
"bom_no":"BOM-_Test PPT Item Sub B-001",
|
||||
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
|
||||
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
|
||||
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
|
||||
"doctype":"BOM Item", "qty":2, "rate":100,
|
||||
"doctype":"BOM Item", "stock_qty":2, "rate":100,
|
||||
"amount": 200},
|
||||
{"item_code": "_Test PPT Item SC A","item_name": "_Test PPT Item SC A",
|
||||
"bom_no":"BOM-_Test PPT Item SC A-001",
|
||||
"doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}
|
||||
"doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}
|
||||
])
|
||||
|
||||
|
||||
@ -388,4 +388,4 @@ def get_requested_types(item_code):
|
||||
where item.item_code = %(item_code)s and item.parent = mat_req.name""", {"item_code":item_code}, as_dict=1):
|
||||
types.append(d.type)
|
||||
return types
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ def get_item_list(prod_list, filters):
|
||||
|
||||
item_list = frappe.db.sql("""SELECT
|
||||
bom_item.item_code as item_code,
|
||||
ifnull(ledger.actual_qty*bom.quantity/bom_item.qty,0) as build_qty
|
||||
ifnull(ledger.actual_qty*bom.quantity/bom_item.stock_qty,0) as build_qty
|
||||
FROM
|
||||
`tabBOM` as bom, `tabBOM Item` AS bom_item
|
||||
LEFT JOIN `tabBin` AS ledger
|
||||
|
@ -403,8 +403,9 @@ erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
|
||||
erpnext.patches.v8_0.delete_bin_indexes
|
||||
erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory
|
||||
erpnext.patches.v8_0.change_in_words_varchar_length
|
||||
erpnext.patches.v8_0.update_stock_qty_value_in_bom_item
|
||||
erpnext.patches.v8_0.create_domain_docs #16-05-2017
|
||||
erpnext.patches.v8_0.update_sales_cost_in_project
|
||||
erpnext.patches.v8_0.save_system_settings
|
||||
erpnext.patches.v8_1.delete_deprecated_reports
|
||||
erpnext.patches.v8_1.setup_gst_india
|
||||
erpnext.patches.v8_1.setup_gst_india #2017-06-27
|
||||
|
13
erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py
Normal file
13
erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('manufacturing', 'doctype', 'bom_item')
|
||||
frappe.reload_doc('manufacturing', 'doctype', 'bom_explosion_item')
|
||||
frappe.reload_doc('manufacturing', 'doctype', 'bom_scrap_item')
|
||||
frappe.db.sql("update `tabBOM Item` set stock_qty = qty, uom = stock_uom, conversion_factor = 1")
|
||||
frappe.db.sql("update `tabBOM Explosion Item` set stock_qty = qty")
|
||||
frappe.db.sql("update `tabBOM Scrap Item` set stock_qty = qty")
|
@ -7,9 +7,25 @@ import frappe
|
||||
def execute():
|
||||
""" delete deprecated reports """
|
||||
|
||||
reports = ["Monthly Salary Register", "Customer Addresses And Contacts",
|
||||
"Supplier Addresses And Contacts"]
|
||||
reports = [
|
||||
"Monthly Salary Register", "Customer Addresses And Contacts",
|
||||
"Supplier Addresses And Contacts"
|
||||
]
|
||||
|
||||
for report in reports:
|
||||
if frappe.db.exists("Report", report):
|
||||
frappe.delete_doc("Report", report, ignore_permissions=True)
|
||||
check_and_update_desktop_icon_for_report(report)
|
||||
frappe.delete_doc("Report", report, ignore_permissions=True)
|
||||
|
||||
def check_and_update_desktop_icon_for_report(report):
|
||||
""" delete desktop icon for deprecated desktop icon and update the _report for Addresses And Contacts"""
|
||||
|
||||
if report == "Monthly Salary Register":
|
||||
frappe.delete_doc("Desktop Icon", report)
|
||||
|
||||
elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]:
|
||||
name = frappe.db.get_value("Desktop Icon", {"_report": report})
|
||||
if name:
|
||||
frappe.db.set_value("Desktop Icon", name, "_report", "Addresses And Contacts")
|
||||
|
||||
frappe.db.commit()
|
||||
|
@ -2,6 +2,7 @@ import frappe
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('regional', 'doctype', 'gst_settings')
|
||||
frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
|
||||
|
||||
for report_name in ('GST Sales Register', 'GST Purchase Register',
|
||||
@ -11,15 +12,23 @@ def execute():
|
||||
|
||||
if frappe.db.get_single_value('System Settings', 'country')=='India':
|
||||
from erpnext.regional.india.setup import setup
|
||||
delete_custom_field_tax_id_if_exists()
|
||||
setup(patch=True)
|
||||
send_gst_update_email()
|
||||
|
||||
def delete_custom_field_tax_id_if_exists():
|
||||
for field in frappe.db.sql_list("""select name from `tabCustom Field` where fieldname='tax_id'
|
||||
and dt in ('Sales Order', 'Salse Invoice', 'Delivery Note')"""):
|
||||
frappe.delete_doc("Custom Field", field, ignore_permissions=True)
|
||||
frappe.db.commit()
|
||||
|
||||
def send_gst_update_email():
|
||||
message = """Hello,
|
||||
|
||||
<p>ERPNext is now GST Ready.</p>
|
||||
<p>ERPNext is now GST Ready!</p>
|
||||
|
||||
<p>To start making GST Invoices from 1st of July, you just need to create new Tax Accounts, Templates and update your Customer's and Supplier's GST Numbers.</p>
|
||||
<p>To start making GST Invoices from 1st of July, you just need to create new Tax Accounts,
|
||||
Templates and update your Customer's and Supplier's GST Numbers.</p>
|
||||
|
||||
<p>Please refer {gst_document_link} to know more about how to setup and implement GST in ERPNext.</p>
|
||||
|
||||
@ -29,5 +38,7 @@ def send_gst_update_email():
|
||||
ERPNext Team.
|
||||
""".format(gst_document_link="<a href='http://frappe.github.io/erpnext/user/manual/en/regional/india/'> ERPNext GST Document </a>")
|
||||
|
||||
sendmail_to_system_managers("[Important] ERPNext GST updates", message)
|
||||
|
||||
try:
|
||||
sendmail_to_system_managers("[Important] ERPNext GST updates", message)
|
||||
except Exception as e:
|
||||
pass
|
0
erpnext/regional/doctype/gst_settings/__init__.py
Normal file
0
erpnext/regional/doctype/gst_settings/__init__.py
Normal file
25
erpnext/regional/doctype/gst_settings/gst_settings.js
Normal file
25
erpnext/regional/doctype/gst_settings/gst_settings.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('GST Settings', {
|
||||
refresh: function(frm) {
|
||||
frm.add_custom_button('Send GST Update Reminder', () => {
|
||||
return new Promise((resolve) => {
|
||||
return frappe.call({
|
||||
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_reminder'
|
||||
}).always(() => { resolve(); });
|
||||
});
|
||||
});
|
||||
|
||||
$(frm.fields_dict.gst_summary.wrapper).empty().html(
|
||||
`<table class="table table-bordered">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Addresses</td><td>${frm.doc.__onload.data.total_addresses}</td>
|
||||
</tr><tr>
|
||||
<td>Total Addresses with GST</td><td>${frm.doc.__onload.data.total_addresses_with_gstin}</td>
|
||||
</tr>
|
||||
</tbody></table>`
|
||||
);
|
||||
}
|
||||
});
|
101
erpnext/regional/doctype/gst_settings/gst_settings.json
Normal file
101
erpnext/regional/doctype/gst_settings/gst_settings.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2017-06-27 15:09:01.318003",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "gst_summary",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "GST Summary",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "gstin_email_sent_on",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "GSTIN Email Sent On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-28 16:20:21.206397",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Regional",
|
||||
"name": "GST Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
97
erpnext/regional/doctype/gst_settings/gst_settings.py
Normal file
97
erpnext/regional/doctype/gst_settings/gst_settings.py
Normal file
@ -0,0 +1,97 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, os
|
||||
from frappe.utils import get_url, nowdate, date_diff
|
||||
from frappe.model.document import Document
|
||||
from frappe.contacts.doctype.contact.contact import get_default_contact
|
||||
|
||||
class EmailMissing(frappe.ValidationError): pass
|
||||
|
||||
class GSTSettings(Document):
|
||||
def onload(self):
|
||||
data = frappe._dict()
|
||||
data.total_addresses = frappe.db.sql('''select count(*) from tabAddress where country = "India"''')
|
||||
data.total_addresses_with_gstin = frappe.db.sql('''select distinct count(*)
|
||||
from tabAddress where country = "India" and ifnull(gstin, '')!='' ''')
|
||||
self.set_onload('data', data)
|
||||
|
||||
@frappe.whitelist()
|
||||
def send_reminder():
|
||||
frappe.has_permission('GST Settings', throw=True)
|
||||
|
||||
last_sent = frappe.db.get_single_value('GST Settings', 'gstin_email_sent_on')
|
||||
if last_sent and date_diff(nowdate(), last_sent) < 3:
|
||||
frappe.throw("Please wait 3 days before resending the reminder.")
|
||||
|
||||
frappe.db.set_value('GST Settings', 'GST Settings', 'gstin_email_sent_on', nowdate())
|
||||
|
||||
# enqueue if large number of customers, suppliser
|
||||
frappe.enqueue('erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder_to_all_parties')
|
||||
frappe.msgprint('Email Reminders will be sent to all parties with email contacts')
|
||||
|
||||
def send_gstin_reminder_to_all_parties():
|
||||
parties = []
|
||||
for address_name in frappe.db.sql('''select name
|
||||
from tabAddress where country = "India" and ifnull(gstin, '')='' '''):
|
||||
address = frappe.get_doc('Address', address_name[0])
|
||||
for link in address.links:
|
||||
party = frappe.get_doc(link.link_doctype, link.link_name)
|
||||
if link.link_doctype in ('Customer', 'Supplier'):
|
||||
t = (link.link_doctype, link.link_name, address.email_id)
|
||||
if not t in parties:
|
||||
parties.append(t)
|
||||
|
||||
sent_to = []
|
||||
for party in parties:
|
||||
# get email from default contact
|
||||
try:
|
||||
email_id = _send_gstin_reminder(party[0], party[1], party[2], sent_to)
|
||||
sent_to.append(email_id)
|
||||
except EmailMissing:
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def send_gstin_reminder(party_type, party):
|
||||
'''Send GSTIN reminder to one party (called from Customer, Supplier form)'''
|
||||
frappe.has_permission(party_type, throw=True)
|
||||
email = _send_gstin_reminder(party_type ,party)
|
||||
if email:
|
||||
frappe.msgprint('Reminder to update GSTIN Sent', title='Reminder sent', indicator='green')
|
||||
|
||||
def _send_gstin_reminder(party_type, party, default_email_id=None, sent_to=None):
|
||||
'''Send GST Reminder email'''
|
||||
email_id = frappe.db.get_value('Contact', get_default_contact(party_type, party), 'email_id')
|
||||
if not email_id:
|
||||
# get email from address
|
||||
email_id = default_email_id
|
||||
|
||||
if not email_id:
|
||||
frappe.throw('Email not found in default contact', exc=EmailMissing)
|
||||
|
||||
if sent_to and email_id in sent_to:
|
||||
return
|
||||
|
||||
frappe.sendmail(
|
||||
subject='Please update your GSTIN',
|
||||
recipients=email_id,
|
||||
message='''
|
||||
<p>Hello,</p>
|
||||
<p>Please help us send you GST Ready Invoices.</p>
|
||||
<p>
|
||||
<a href="{0}?party={1}">
|
||||
Click on the here to update your GSTIN Number in our system
|
||||
</a>
|
||||
</p>
|
||||
<p style="color: #aaa; font-size: 11px; margin-top: 30px;">
|
||||
Get your GST Ready ERP system at <a href="https://erpnext.com">https://erpnext.com</a>
|
||||
<br>
|
||||
ERPNext is a free and open source ERP system.
|
||||
</p>
|
||||
'''.format(os.path.join(get_url(), '/regional/india/update-gstin'), party)
|
||||
)
|
||||
|
||||
return email_id
|
25
erpnext/regional/india/party.js
Normal file
25
erpnext/regional/india/party.js
Normal file
@ -0,0 +1,25 @@
|
||||
erpnext.setup_gst_reminder_button = (doctype) => {
|
||||
frappe.ui.form.on(doctype, {
|
||||
refresh: (frm) => {
|
||||
if(!frm.is_new()) {
|
||||
var missing = false;
|
||||
frm.doc.__onload.addr_list && frm.doc.__onload.addr_list.forEach((d) => {
|
||||
if(!d.gstin) missing = true;
|
||||
});
|
||||
if (!missing) return;
|
||||
|
||||
frm.add_custom_button('Send GST Update Reminder', () => {
|
||||
return new Promise((resolve) => {
|
||||
return frappe.call({
|
||||
method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder',
|
||||
args: {
|
||||
party_type: frm.doc.doctype,
|
||||
party: frm.doc.name,
|
||||
}
|
||||
}).always(() => { resolve(); });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
@ -65,7 +65,7 @@ def add_custom_roles_for_reports():
|
||||
)).insert()
|
||||
|
||||
def add_permissions():
|
||||
for doctype in ('GST HSN Code',):
|
||||
for doctype in ('GST HSN Code', 'GST Settings'):
|
||||
add_permission(doctype, 'Accounts Manager', 0)
|
||||
add_permission(doctype, 'All', 0)
|
||||
|
||||
|
3
erpnext/selling/doctype/customer/regional/india.js
Normal file
3
erpnext/selling/doctype/customer/regional/india.js
Normal file
@ -0,0 +1,3 @@
|
||||
{% include "erpnext/regional/india/party.js" %}
|
||||
|
||||
erpnext.setup_gst_reminder_button('Customer')
|
0
erpnext/templates/pages/regional/__init__.py
Normal file
0
erpnext/templates/pages/regional/__init__.py
Normal file
0
erpnext/templates/pages/regional/india/__init__.py
Normal file
0
erpnext/templates/pages/regional/india/__init__.py
Normal file
37
erpnext/templates/pages/regional/india/update-gstin.html
Normal file
37
erpnext/templates/pages/regional/india/update-gstin.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends "templates/web.html" %}
|
||||
|
||||
{% block title %}Update GSTIN{% endblock %}
|
||||
|
||||
{% block header %}<h2>Update GSTIN</h2>{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<h3>{{ party.name }}</h3>
|
||||
{% if invalid_gstin %}
|
||||
<p class='alert alert-danger' style='max-width: 300px;'>
|
||||
Invalid GSTIN
|
||||
</p>
|
||||
<p>
|
||||
<a href="?party={{ party.name }}">Edit Again</a>
|
||||
</p>
|
||||
{% elif updated %}
|
||||
<p class='alert alert-success' style='max-width: 300px;'>
|
||||
<i class='octicon octicon-check'></i> GSTIN Updated
|
||||
</p>
|
||||
<p>
|
||||
<a href="?party={{ party.name }}">Edit Again</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p class='text-muted'>Please update your GSTIN for us to issue correct tax invoice</p>
|
||||
<form method='GET' action='/regional/india/update-gstin.html'>
|
||||
<input type='hidden' value='{{ party.name }}' name='party'>
|
||||
{% for address in party.__onload.addr_list %}
|
||||
<div class='bordered' style='max-width: 300px; margin-bottom: 15px;'>
|
||||
{{ address.display }}
|
||||
<p><input type='text' class='form-control'
|
||||
value='{{ address.gstin or "" }}' name='{{ address.name }}' placeholder='GSTIN'></p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p><input type='submit' class='btn btn-primary' value='Update'></p>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock %}
|
40
erpnext/templates/pages/regional/india/update_gstin.py
Normal file
40
erpnext/templates/pages/regional/india/update_gstin.py
Normal file
@ -0,0 +1,40 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
party = frappe.form_dict.party
|
||||
|
||||
try:
|
||||
update_gstin(context)
|
||||
except frappe.ValidationError:
|
||||
context.invalid_gstin = 1
|
||||
|
||||
party_type = 'Customer'
|
||||
party = frappe.db.get_value('Customer', party)
|
||||
|
||||
if not party:
|
||||
party_type = 'Supplier'
|
||||
party = frappe.db.get_value('Supplier', party)
|
||||
|
||||
if not party:
|
||||
frappe.throw(_("Not Found"), frappe.DoesNotExistError)
|
||||
|
||||
context.party = frappe.get_doc(party_type, party)
|
||||
context.party.onload()
|
||||
|
||||
|
||||
def update_gstin(context):
|
||||
dirty = False
|
||||
for key, value in frappe.form_dict.items():
|
||||
if key != 'party':
|
||||
address_name = frappe.get_value('Address', key)
|
||||
if address_name:
|
||||
address = frappe.get_doc('Address', address_name)
|
||||
address.gstin = value
|
||||
address.save(ignore_permissions=True)
|
||||
dirty = True
|
||||
|
||||
if dirty:
|
||||
frappe.db.commit()
|
||||
context.updated = True
|
Loading…
x
Reference in New Issue
Block a user