Merge branch 'master' of github.com:webnotes/erpnext into wsgi

Conflicts:
	accounts/doctype/sales_invoice/sales_invoice.txt
	controllers/selling_controller.py
	patches/patch_list.py
	selling/doctype/lead/lead.py
	selling/doctype/opportunity/opportunity.py
	selling/doctype/quotation/quotation.py
	selling/doctype/quotation/quotation.txt
	selling/doctype/sales_order/sales_order.txt
	stock/doctype/purchase_receipt/purchase_receipt.py
	stock/doctype/serial_no/serial_no.py
	stock/doctype/stock_entry/stock_entry.py
	stock/doctype/stock_ledger_entry/stock_ledger_entry.py
This commit is contained in:
Anand Doshi 2013-10-15 12:18:46 +05:30
commit 7e9048570e
44 changed files with 902 additions and 332 deletions

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-24 12:15:51",
"docstatus": 0,
"modified": "2013-08-28 19:13:42",
"modified": "2013-10-15 11:12:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -80,16 +80,6 @@
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "conversion_rate",
"fieldtype": "Float",
"label": "Conversion Rate",
"oldfieldname": "conversion_rate",
"oldfieldtype": "Currency",
"read_only": 0,
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "selling_price_list",

View File

@ -147,7 +147,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
});
}
}
},
debit_to: function() {

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:05",
"docstatus": 0,
"modified": "2013-10-03 18:54:31",
"modified": "2013-10-11 13:12:38",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -226,7 +226,6 @@
"reqd": 1
},
{
"default": "1.00",
"description": "Rate at which Customer Currency is converted to customer's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",

View File

@ -52,7 +52,7 @@ class AccountsController(TransactionBase):
msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") +
self.doc.doctype + _(" can not be made."), raise_exception=1)
def set_price_list_currency(self, buying_or_selling):
def set_price_list_currency(self, buying_or_selling, for_validate=False):
if self.meta.get_field("currency"):
company_currency = get_company_currency(self.doc.company)
@ -60,14 +60,13 @@ class AccountsController(TransactionBase):
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
else "buying_price_list"
if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname):
if not self.doc.price_list_currency:
self.doc.price_list_currency = webnotes.conn.get_value("Price List",
self.doc.fields.get(fieldname), "currency")
self.doc.price_list_currency = webnotes.conn.get_value("Price List",
self.doc.fields.get(fieldname), "currency")
if self.doc.price_list_currency == company_currency:
self.doc.plc_conversion_rate = 1.0
elif not self.doc.plc_conversion_rate:
elif not self.doc.plc_conversion_rate or not for_validate:
self.doc.plc_conversion_rate = self.get_exchange_rate(
self.doc.price_list_currency, company_currency)
@ -77,7 +76,7 @@ class AccountsController(TransactionBase):
self.doc.conversion_rate = self.doc.plc_conversion_rate
elif self.doc.currency == company_currency:
self.doc.conversion_rate = 1.0
elif not self.doc.conversion_rate:
elif not self.doc.conversion_rate or not for_validate:
self.doc.conversion_rate = self.get_exchange_rate(self.doc.currency,
company_currency)

View File

@ -29,7 +29,7 @@ class BuyingController(StockController):
super(BuyingController, self).set_missing_values(for_validate)
self.set_supplier_from_item_default()
self.set_price_list_currency("Buying")
self.set_price_list_currency("Buying", for_validate)
# set contact and address details for supplier, if they are not mentioned
if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address):

View File

@ -23,7 +23,7 @@ class SellingController(StockController):
# set contact and address details for customer, if they are not mentioned
self.set_missing_lead_customer_details()
self.set_price_list_and_item_details()
self.set_price_list_and_item_details(for_validate)
if self.doc.fields.get("__islocal"):
self.set_taxes("other_charges", "charge")
@ -41,8 +41,8 @@ class SellingController(StockController):
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
self.doc.fields[fieldname] = val
def set_price_list_and_item_details(self):
self.set_price_list_currency("Selling")
def set_price_list_and_item_details(self, for_validate=False):
self.set_price_list_currency("Selling", for_validate)
self.set_missing_item_details(get_item_details)
def get_other_charges(self):

View File

@ -13,33 +13,34 @@ You can make a Sales Invoice of type POS by checking on “Is POS”. When you c
- Update Stock: If this is checked, Stock Ledger Entries will be made when you “Submit” this Sales Invoice thereby eliminating the need for a separate Delivery Note.
- In your Items table, update inventory information like Warehouse (saved as default), Serial Number, or Batch Number if applicable.
- Update Payment Details like your Bank / Cash Account, paid amount etc.
- Update Payment Details like your Bank / Cash Account, Paid amount etc.
- If you are writing off certain amount. For example when you receive extra cash as a result of not having exact denomination of change, check on Write off Outstanding Amount and set the Account.
Setup [POS Setting](docs.user.setup.pos_setting.html)
#### Enable POS View
Sales Invoice has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred.
- Every Sales & Purchase documents has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred.
> Setup > Show/Hide Features
![POS View](img/pos-features-setup.png)
- Setup [POS Setting](docs.user.setup.pos_setting.html)
### Adding an Item
At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode.
At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode / Serial No.
**Select Item** - To select a product click on the Item image and add it into the cart. A cart is an area that prepares a customer for checkout by allowing to edit product information, adjust taxes and add discounts.
**Barcode** - A Barcode is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode in the barcode box and pause for a second. The Item will be automatically added to the cart.
**Barcode / Serial No** - A Barcode / Serial No is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode / Serial No in the box as shown in the image below and pause for a second, the item will be automatically added to the cart.
![POS](img/pos-add-item.png)
> Tip: To change the quantity of an Item, enter your desired quantity in the quantity box. These are mostly used if the same Item is purchased in bulk.
If your product list is very long use the universal search field, to type the product name and select faster.
If your product list is very long use the Search field, type the product name in Search box.
### Removing an Item
@ -48,7 +49,7 @@ There are two ways to remove an Item.
- Select an Item by clicking on the row of that Item from Item cart. Then click on “Del” button. OR
- Type 0 in the select quantity field to delete the record.
- Enter 0(zero) quantity of any item to delete that item.
To remove multiple Items together, select multiple rows & click on “Del” button.
@ -62,11 +63,11 @@ After all the Items and their quantities are added into the cart, you are ready
1. Click on “Make Payment” to get the Payment window.
1. Select your “Mode of Payment”.
1. Click on “Pay” button to Save the Sales Invoice.
1. Click on “Pay” button to Save the document.
![POS Payment](img/pos-make-payment.png)
Submit the document to finalise the record. After the Invoice is submitted, you can either print an invoice or email it directly to the customer.
Submit the document to finalise the record. After the document is submitted, you can either print or email it directly to the customer.
#### Accounting entries (GL Entry) for a Point of Sale:

View File

@ -3,6 +3,7 @@
"_label": "User Guide",
"_toc": [
"docs.user.intro",
"docs.user.five_day_setup",
"docs.user.implement",
"docs.user.setup",
"docs.user.selling",
@ -17,7 +18,7 @@
"docs.user.tools",
"docs.user.customize",
"docs.user.knowledge"
],
],
"_no_toc": 1
}
---
@ -29,6 +30,12 @@ Contents
1. [Open Source](docs.user.intro.open_source.html)
1. [Ways to get started](docs.user.intro.try.html)
1. [Getting Help](docs.user.help.html)
1. [Five-Day-Setup](docs.user.five_day_setup.html)
1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html)
1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html)
1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html)
1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html)
1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html)
1. [Implementation](docs.user.implement.html)
1. [Implementation Strategy](docs.user.implement.strategy.html)
1. [Concepts](docs.user.implement.concepts.html)
@ -154,4 +161,3 @@ Contents
1. [DocType Definitions](docs.user.knowledge.doctype.html)
1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html)
1. [Format using Markdown](docs.user.knowledge.markdown.html)

View File

@ -0,0 +1,81 @@
---
{
"_label": "Day-1: Setup Customer, Item, and Supplier"
}
---
Login to your ERPNext account with the User ID and Password sent through the mail.
After logging into your account you will receive a pop-up form to fill. Please fill this form. Select the abbreviation you would wish to have for your company. The abbreviation selected here will be used in naming most of the business documents.
#### Form Part I
![1st Form](img/firstdaysetup-1.png)
<br><br>
#### Form Part II
To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html)
![1st Form](img/firstdaysetup-2.png)
After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear.
<br>
#### Setup Page - Customer
The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon.
![Customer](img/firstdaysetup-customer.png)
<br>
After clicking on Customer, a new form will appear.
<br>
![Customer](img/firstdaysetup-customer-1.png)
To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system.
Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup
![Main Menu](img/firstdaysetup-main-menu.png)
<br>
#### Setup Page - Item
On the setup page go to Item.
![Item](img/firstdaysetup-item.png)
Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers.
Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item.
![Item](img/firstdaysetup-item-1.png)
To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers.
<br>
#### Setup Page - Suppliers
On the Setup page go to Supplier.
![Supplier](img/firstdaysetup-supplier.png)
<br>
Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record.
![Supplier](img/firstdaysetup-supplier-1.png)
To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html).
If you wish to import your list of customers and suppliers directly to ERPNext, you can do that via the Data Import Tool.
To upload Customers or suppliers in bulk, go to the Data Import Tool.
> Note: The data import format is case-sensitive. The file will not be processed if there are any spelling mistakes or deviations from the default values.
To understand how to import data, visit [Importing Data](docs.user.setup.data_import.html).

View File

@ -0,0 +1,54 @@
---
{
"_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR"
}
---
#### Setup Page - Accounts
<br>
Go to the Accounts icon and make ledgers under Chart of Accounts.
![Accounts](img/seconddaysetup-accounts.png)
<br>
Create acccounting ledgers.
![Tree](img/seconddaysetup-tree.png)
<br>
To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page.
![Ledger](img/seconddaysetup-accounts-jv.png)
<br>
To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html).
<br>
#### Opening Stock
You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item.
![Stock Opening](img/seconddaysetup-stock-opening.png)
<br>
To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html).
<br>
#### Setup Page - HR Setup
To setup HR, begin by creating individual employee records.
![Employee](img/seconddaysetup-hr.png)
To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html)
To complete the remaining HR-Setup, see [Human Resources](docs.user.hr.html)

View File

@ -0,0 +1,139 @@
---
{
"_label": "Day-3: Sales Cycle and Purchase Cycle"
}
---
After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process.
### Sales Cycle
Complete a standard Sales Cycle.
> Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher)
<br>
#### Lead
To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead.
![Lead](img/thirddaysetup-lead.png)
Fill the Lead form.
> To understand Lead in detail, visit [Lead](docs.user.selling.lead.html)
<br>
#### Opportunity
After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page.
##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status.
![Opportunity](img/thirddaysetup-opportunity-1.png)
<br>
##### Step 2: Generate Opportunity from the selected Lead
![Opportunity](img/thirddaysetup-opportunity.png)
You can also generate an Opportunity directly from the Selling Page.
> To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html).
<br>
#### Quotation
Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation.
![Quotation](img/thirddaysetup-quotation.png)
You can also generate a Quotation directly from the Selling Page.
> To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html)
<br>
#### Sales Order
Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order.
![Sales Order](img/thirddaysetup-sales-order.png)
You can also generate a Sales Order directly from the Selling Page.
> To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html).
<br>
#### Delivery Note
If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery.
![Delivery Note](img/thirddaysetup-delivery-note.png)
> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html)
<br>
#### Sales Invoice
Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order.
![Sales Invoice](img/thirddaysetup-sales-invoice.png)
<br>
#### Payment (Journal Voucher)
A Journal Voucher or a payment entry can be generated directly from the Sales Invoice.
![Payment Entry](img/thirddaysetup-payment-entry.png)
> To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html)
<br>
### Purchase Cycle
Complete a standard Purchase Cycle.
> Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
<br>
#### Material Request
To create a Material Request, go to Stock/Buying and Click on Material Request.
![Material Request](img/thirddaysetup-material-request.png)
> To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html)
<br>
#### Purchase Order
To create a Purchase Order go to Buying and click on Purchase Order
![Purchase Order](img/thirddaysetup-purchase-order.png)
> To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html)
<br>
#### Purchase Receipt
To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt.
![Purchase Receipt](img/thirddaysetup-purchase-receipt.png)
<br>
>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html)
<br>
#### Payment (Journal Voucher)
Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices.
![Payment Entry](img/thirddaysetup-payment-entry.png)
<br>
> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html).

View File

@ -0,0 +1,86 @@
---
{
"_label": "Day-4: Manufacturing Cycle and Accounting Reports"
}
---
### Manufacturing Cycle
Complete a manufacturing cycle (if applicable).
> BOM > Production Planning Tool > Production Order > Stock Entry (Material Issue) > Stock Entry (Sales Return)
<br>
#### Bill of Materials
To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials.
![Bill of Materials](img/fourthdaysetup-bom.png)
> To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html)
<br>
#### Production Planning Tool
To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page.
![Production Planning Page](img/fourthdaysetup-ppt.png)
> To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html)
<br>
#### Production Order
To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order.
![Production Order](img/fourthdaysetup-po.png)
> To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html)
<br>
#### Stock Entry
To go to Stock Entry, click on the Stock Icon and go to Stock Entry.
![Stock Entry](img/fourthdaysetup-stock.png)
> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html).
> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html).
<br>
#### Delivery Note
To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note.
![Delivery Note](img/fourthdaysetup-delivery-note.png)
> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html)
<br>
#### Warehouse
To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse.
![Warehouse](img/fourthdaysetup-warehouse.png)
> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html)
<br>
#### Accounts
Make a few Journal Vouchers. Generate some Accounting Reports.
#### Journal Voucher
To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher.
![Journal Voucher](img/fourthdaysetup-jv.png)
> To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html)
<br>
### Accounting Reports
Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register.
> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html)

View File

@ -0,0 +1,32 @@
---
{
"_label": "Day-5: Projects, Calendar, and Website"
}
---
#### Projects
ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people.
<br>
#### Tasks
Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project.
To create a Task, go to Project and click on Task.
![Tasks](img/fifthdaysetup-tasks.png)
> To understand Projects in detail, visit [Projects](docs.user.projects.html).
> To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html)
<br>
#### Calendar
> To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html)
<br>
#### Website
> To understand Website in detail, visit [Website](docs.user.website.html)

View File

@ -0,0 +1,48 @@
---
{
"_label": "Five-Day Setup",
"_toc": [
"docs.user.five_day_setup.day_1",
"docs.user.five_day_setup.day_2",
"docs.user.five_day_setup.day_3",
"docs.user.five_day_setup.day_4",
"docs.user.five_day_setup.day_5"
]
}
---
Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation.
The setup help is divided into day-wise instructions for 5 consecutive days.
#### Day 1
- Company Setup
- Customer Setup
- Item Setup
- Supplier Setup
- Data Import Tool
#### Day 2
- Opening Accounts
- Opening Stock
- HR Setup
#### Day 3
- Sales Cycle
- Purchase Cycle
#### Day 4
- Manufacturing Cycle
- Delivery Note and Warehouse
- Accounts
#### Day 5
- Projects
- Calendar
- Website

View File

@ -10,11 +10,12 @@ Before you start managing your Operations in EPRNext, you must first become fami
### Test Phase
- Read the Manual
- Follow the Five-Day-Setup Module or the instructions given below.
- Create your first Customer, Supplier and Item. Add a few more so you get familiar with them.
- Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items.
- Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher)
- Complete a standard purchase cycle - Purchase Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush)
- Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Material Issue > Sales Return
> Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive.

View File

@ -1,6 +1,6 @@
---
{
"_label": "Attachement and CSV files"
"_label": "Attachment and CSV files"
}
---

View File

@ -45,6 +45,14 @@ ERPNext will help you set and manage budgets on your Cost Centers. This is usefu
Budgets are also great for planning purposes. When you are making plans for the next financial year, you would typically target a revenue based on which you would set your expenses. Setting a budget will ensure that your expenses do not get out of hand, at any point, as per your plans.
You can define it in the Cost Center. If you have seasonal sales you can also define a budget distribution that the budget will follow.
> Accounts > Budget Distribution > New Budget Distribution
![Budget Distribution](img/budgeting.png)
#### Budget Actions

View File

@ -18,7 +18,7 @@
"docs.user.setup.email",
"docs.user.setup.sms",
"docs.user.setup.taxes",
"docs.user.setup.price_lists",
"docs.user.setup.price_list",
"docs.user.setup.opening",
"docs.user.setup.pos_setting",
"docs.user.setup.third_party_backups"

View File

@ -7,7 +7,7 @@ A Price List is a place where different rate plans can be stored. Its a name
An Item can have multiple prices based on customer, currency, region, shipping cost etc, which can be stored as different rate plans. In ERPNext, you are required to store all the lists seperately. Buying Price List is different from Selling Price List and thus is stored separately.
> Selling > Price List
> Setup > Price List
![Price-List](img/price-lists.png)
@ -15,7 +15,14 @@ An Item can have multiple prices based on customer, currency, region, shipping c
> For multiple currencies, maintain multiple Price Lists.
<br>
### Add Item in Price List
To add a new Item to the Price List, add the Item Code and its rate in the Item Prices table.
> Setup > Item Price
You can also import Item Prices via [Data Import Tool](docs.user.setup.data_import.html)
- Enter Price List and Item Code, Valid for Buying or Selling, Item Name & Item Description will be automatically fetched.
- Enter Rate and save the document.
![Item-Price](img/item-price.png)
For bulk upload of Item Prices, use [Data Import Tool](docs.user.setup.data_import.html)

View File

@ -6,7 +6,7 @@
ERPNext has a role-based permission system, which means that you can assign Roles to Users, and permissions on Roles.Each ERPNext user has a Profile. The Profile contains the users email and authentication and can be set from:
> Setup > Users and Permissions > Users
> Setup > Profile
#### Step 1: Adding a new User

View File

@ -15,7 +15,7 @@ ERPNext is optimized for itemized management of your sales and purchase. If you
- **Item Name:** Item name is the actual name of your product or service.
- **Item Code:** Item Code is a short-form to denote your Item. If you have very few Items, it is advisable to keep the Item Name and the Item Code same. This helps new users to recognise and update Item details in all transactions. In case you have lot of Items with long names and the list runs in hundreds, it is advisable to code. To understand naming Item codes see [Item Codification](docs.user.setup.codification.html)
- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under Item Group.
- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under [Item Group](docs.user.stock.item_group.html)
- **Default Unit of Measure:** This is the default measuring unit that you will use for your product. It could be in nos, kgs, meters, etc. You can store all the UOMs that your product will require under Set Up> Master Data > UOM. These can be preselected while filling New Item by using % sign to get a pop up of the UOM list.
- **Brand:** If you have more than one brand save them under Set Up> Master Data> Brand and pre-select them while filling a New Item.
@ -91,3 +91,59 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi
Visit [Manufacturing](docs.user.mfg.html) and [Website](docs.user.website.html) to understand these topics in detail.
### Listing Item on Website
To list your Item on the Website, fill the Item details and save the file. Once the file is saved, a plus (+) button will appear next to the Image icon. Click on the plus button and add your Item image. The html code will be generated automatically.
##### Step 1: Save Image
![Webimage](img/item-webimage.png)
<br>
##### Step 2: Check the 'Show in Website' box.
Under the Website section, please check the box that says 'show in Website'. Once the box is checked, the page will display other fields for entering information.
![Webimage](img/item-webimage-1.png)
<br>
##### Step 3: Enter Website Details
![Webimage](img/item-webimage-2.png)
The page name will be generated automatically. Mention the Item-Group under which the Item will be displayed.
#### Item Groups
Mention the Item Group under this column. If you wish to list your Item under the broad category products, name your Item Group as Products. In case you have various varieties of Item and want to classify them under different names, make Item Groups with those names and check the box that says 'show in Website'. For Example, if you wish to create a category called 'Bags', create a Item Group named Bags.
![Item Group](img/itemgroup-webimage-bags.png)
Once the Item Group is created go to the Website Settings page under Website. Enter the Label, Url, and Parent Label.
![Item Group](img/itemgroup-website-settings.png)
<br>
#### Webpage labels
![Webpage](img/webpage-labels.png)
Add more Items under a particular Item Group.
To add more Items under a certain Label, mention the Item Group on the Item Page. The Items will be added automatically on the Webpage, under the Item Group Label. For Example, To add Item-Kiddies Bag and Butterfly Print Bag, check the 'Show in Website'box. The Items will be placed under the Label Bags on the Webpage.
![Item Group](img/itemgroup-websettings.png)
<br>
Item Group Display
![Item Group Display](img/webpage-itemgroup-display.png)

View File

@ -15,6 +15,11 @@ To create a new blog, just create a new Blog from:
![Blog](img/blog.png)
You can format the blog using the same Markdown format
You can format a blog using the Markdown format.You can also access your blog by going to the page “blog.html”.
#### A sample blog-page.
![Blog](img/blog-look.png)
You can access your blog by going to the page “blog.html”

View File

@ -29,11 +29,36 @@ To define the Top Bar Menus, Brand, Footers and Home Page, go to:
> Website > Website Settings
#### Step 1: Landing Page Details
![Website Setting](img/website-settings.png)
<br>
#### Step 2: Banner Details
![Website Setting](img/website-settings-1.png)
<br>
#### Step 3: Top Bar Labels
![Website Setting](img/website-settings-2.png)
> Note: Create seperate web pages which will be linked to the main web-icons like company, contact, products etc.
<br>
#### Step 4: Footer Details
![Website Setting](img/website-settings-3.png)
A website can be generated once all the settings and style requirements are added.
A sample website generated by ERPNext would look like this.
![Website](img/website-settings-4.png)
<br>
#### Top Menu

View File

@ -17,6 +17,9 @@ class DocType:
self.doclist = doclist
def validate(self):
if self.doc.docstatus == 0:
self.doc.status = "Draft"
import utilities
utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped",
"In Process", "Completed", "Cancelled"])
@ -148,12 +151,6 @@ def get_item_details(item):
@webnotes.whitelist()
def make_stock_entry(production_order_id, purpose):
production_order = webnotes.bean("Production Order", production_order_id)
# validate already existing
ste = webnotes.conn.get_value("Stock Entry", {
"production_order":production_order_id,
"purpose": purpose
}, "name")
stock_entry = webnotes.new_bean("Stock Entry")
stock_entry.doc.purpose = purpose

View File

@ -0,0 +1,75 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import webnotes
from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from manufacturing.doctype.production_order.production_order import make_stock_entry
class TestProductionOrder(unittest.TestCase):
def test_planned_qty(self):
set_perpetual_inventory(0)
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.conn.sql("""delete from `tabBin`""")
webnotes.conn.sql("""delete from `tabGL Entry`""")
pro_bean = webnotes.bean(copy = test_records[0])
pro_bean.insert()
pro_bean.submit()
from stock.doctype.stock_entry.test_stock_entry import test_records as se_test_records
mr1 = webnotes.bean(copy = se_test_records[0])
mr1.insert()
mr1.submit()
mr2 = webnotes.bean(copy = se_test_records[0])
mr2.doclist[1].item_code = "_Test Item Home Desktop 100"
mr2.insert()
mr2.submit()
stock_entry = make_stock_entry(pro_bean.doc.name, "Manufacture/Repack")
stock_entry = webnotes.bean(stock_entry)
stock_entry.doc.fg_completed_qty = 4
stock_entry.run_method("get_items")
stock_entry.submit()
self.assertEqual(webnotes.conn.get_value("Production Order", pro_bean.doc.name,
"produced_qty"), 4)
self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6)
return pro_bean.doc.name
def test_over_production(self):
from stock.doctype.stock_entry.stock_entry import StockOverProductionError
pro_order = self.test_planned_qty()
stock_entry = make_stock_entry(pro_order, "Manufacture/Repack")
stock_entry = webnotes.bean(stock_entry)
stock_entry.doc.fg_completed_qty = 15
stock_entry.run_method("get_items")
stock_entry.insert()
self.assertRaises(StockOverProductionError, stock_entry.submit)
test_records = [
[
{
"bom_no": "BOM/_Test FG Item/001",
"company": "_Test Company",
"doctype": "Production Order",
"production_item": "_Test FG Item",
"qty": 10.0,
"fg_warehouse": "_Test Warehouse 1 - _TC",
"wip_warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
}
]
]

View File

@ -3,16 +3,9 @@
def execute():
import webnotes
from webnotes.utils import flt
bins = webnotes.conn.sql("select item_code, warehouse, name, ordered_qty from `tabBin`")
for d in bins:
ordered_qty = webnotes.conn.sql("""
select sum(ifnull(po_item.qty, 0) - ifnull(po_item.received_qty, 0))
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
where po_item.parent = po.name and po.docstatus = 1 and po.status != 'Stopped'
and po_item.item_code = %s and po_item.warehouse = %s
""", (d[0], d[1]))
if flt(d[3]) != flt(ordered_qty[0][0]):
webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""",
(ordered_qty and ordered_qty[0][0] or 0, d[2]))
from utilities.repost_stock import get_ordered_qty, update_bin
for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
update_bin(d[0], d[1], {
"ordered_qty": get_ordered_qty(d[0], d[1])
})

View File

@ -4,54 +4,10 @@
import webnotes
def execute():
webnotes.conn.auto_commit_on_many_writes = 1
repost_reserved_qty()
webnotes.conn.auto_commit_on_many_writes = 0
from utilities.repost_stock import get_reserved_qty, update_bin
def repost_reserved_qty():
from webnotes.utils import flt
bins = webnotes.conn.sql("select item_code, warehouse, name, reserved_qty from `tabBin`")
i = 0
for d in bins:
i += 1
reserved_qty = webnotes.conn.sql("""
select
sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
from
(
(select
qty as dnpi_qty,
(
select qty from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_qty,
(
select ifnull(delivered_qty, 0) from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_delivered_qty,
parent, name
from
(
select qty, parent_detail_docname, parent, name
from `tabDelivery Note Packing Item` dnpi_in
where item_code = %s and warehouse = %s
and parenttype="Sales Order"
and item_code != parent_item
and exists (select * from `tabSales Order` so
where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
) dnpi)
union
(select qty as dnpi_qty, qty as so_item_qty,
ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
from `tabSales Order Item` so_item
where item_code = %s and reserved_warehouse = %s
and exists(select * from `tabSales Order` so
where so.name = so_item.parent and so.docstatus = 1
and so.status != 'Stopped'))
) tab
where
so_item_qty >= so_item_delivered_qty
""", (d[0], d[1], d[0], d[1]))
if flt(d[3]) != flt(reserved_qty[0][0]):
webnotes.conn.sql("""update `tabBin` set reserved_qty = %s where name = %s""",
(reserved_qty and reserved_qty[0][0] or 0, d[2]))
for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
update_bin(d[0], d[1], {
"reserved_qty": get_reserved_qty(d[0], d[1])
})
webnotes.conn.auto_commit_on_many_writes = 0

View File

@ -0,0 +1,6 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
def execute():
from patches.december_2012 import repost_ordered_qty
repost_ordered_qty.execute()

View File

@ -0,0 +1,11 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
def execute():
import webnotes
from utilities.repost_stock import get_planned_qty, update_bin
for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
update_bin(d[0], d[1], {
"planned_qty": get_planned_qty(d[0], d[1])
})

View File

@ -226,4 +226,6 @@ patch_list = [
"execute:webnotes.delete_doc('DocType', 'Setup Control')",
"patches.october_2013.p04_wsgi_migration",
"patches.october_2013.p05_server_custom_script_to_file",
"patches.october_2013.repost_ordered_qty",
"patches.october_2013.repost_planned_qty",
]

View File

@ -28,9 +28,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
var value_diff = (rate * add_qty);
if(add_qty)
wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl);
wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
} else {
// outgoing
if(sl.serial_no) {
@ -113,7 +111,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
$.each(wn.report_dump.data["Stock Ledger Entry"], function(i, sle) {
if(sle.qty > 0 && sle.serial_no) {
$.each(sle.serial_no.trim().split("\n"), function(i, sr) {
if(sr && sle.incoming_rate !== undefined) {
if(sr && sle.incoming_rate !== undefined
&& !serialized_buying_rates[sr.trim().toLowerCase()]) {
serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate);
}
});

View File

@ -21,8 +21,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
company: wn.defaults.get_default("company"),
fiscal_year: wn.defaults.get_default("fiscal_year"),
is_subcontracted: "No",
conversion_rate: 1.0,
plc_conversion_rate: 1.0
}, function(fieldname, value) {
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
me.frm.set_value(fieldname, value);
@ -41,18 +39,19 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
},
onload_post_render: function() {
if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.customer) {
var me = this;
return this.frm.call({
doc: this.frm.doc,
method: "onload_post_render",
freeze: true,
callback: function(r) {
// remove this call when using client side mapper
me.set_default_values();
me.set_dynamic_labels();
}
});
if(this.frm.doc.__islocal && this.frm.doc.company &&
!this.frm.doc.customer && !this.frm.doc.is_pos) {
var me = this;
return this.frm.call({
doc: this.frm.doc,
method: "onload_post_render",
freeze: true,
callback: function(r) {
// remove this call when using client side mapper
me.set_default_values();
me.set_dynamic_labels();
}
});
}
},
@ -131,10 +130,18 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
company: function() {
if(this.frm.doc.company && this.frm.fields_dict.currency) {
if(!this.frm.doc.currency) {
this.frm.set_value("currency", this.get_company_currency());
var company_currency = this.get_company_currency();
if (!this.frm.doc.currency) {
this.frm.set_value("currency", company_currency);
}
if (this.frm.doc.currency == company_currency) {
this.frm.set_value("conversion_rate", 1.0);
}
if (this.frm.doc.price_list_currency == company_currency) {
this.frm.set_value('plc_conversion_rate', 1.0);
}
this.frm.script_manager.trigger("currency");
}
},
@ -146,15 +153,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
currency: function() {
var me = this;
this.set_dynamic_labels();
var company_currency = this.get_company_currency();
if(this.frm.doc.currency !== company_currency) {
this.get_exchange_rate(this.frm.doc.currency, company_currency,
function(exchange_rate) {
if(exchange_rate) {
me.frm.set_value("conversion_rate", exchange_rate);
me.conversion_rate();
}
me.frm.set_value("conversion_rate", exchange_rate);
me.conversion_rate();
});
} else {
this.conversion_rate();
@ -168,7 +173,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) {
this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
}
this.calculate_taxes_and_totals();
},
@ -233,29 +238,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
this.calculate_taxes_and_totals();
},
// serial_no: function(doc, cdt, cdn) {
// var me = this;
// var item = wn.model.get_doc(cdt, cdn);
// if (!item.item_code) {
// wn.call({
// method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no',
// args: {serial_no: this.serial_no.$input.val()},
// callback: function(r) {
// if (r.message) {
// var item_code = r.message[0].item_code;
// var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item",
// this.frm.cscript.fname);
// child.item_code = item_code;
// me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
// }
// else
// msgprint(wn._("Invalid Serial No."));
// me.refresh();
// }
// });
// }
// },
row_id: function(doc, cdt, cdn) {
var tax = wn.model.get_doc(cdt, cdn);
try {
@ -486,12 +468,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
}
var company_currency = this.get_company_currency();
var valid_conversion_rate = this.frm.doc.conversion_rate ?
((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) ||
(this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) :
false;
if(!valid_conversion_rate) {
if(!this.frm.doc.conversion_rate) {
wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
" 1 " + this.frm.doc.currency + " = [?] " + company_currency);
}

View File

@ -121,4 +121,4 @@ def make_opportunity(source_name, target_doclist=None):
}
}}, target_doclist)
return [d if isinstance(d, dict) else d.fields for d in doclist]
return [d if isinstance(d, dict) else d.fields for d in doclist]

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
"modified": "2013-10-03 16:31:55",
"modified": "2013-10-11 13:21:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -258,7 +258,6 @@
"width": "100px"
},
{
"default": "1.00",
"description": "Rate at which customer's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",

View File

@ -2,7 +2,7 @@
{
"creation": "2013-06-18 12:39:59",
"docstatus": 0,
"modified": "2013-10-02 14:24:37",
"modified": "2013-10-11 13:18:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -273,7 +273,6 @@
"width": "100px"
},
{
"default": "1.00",
"description": "Rate at which customer's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:09",
"docstatus": 0,
"modified": "2013-08-09 14:46:32",
"modified": "2013-10-11 13:19:40",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -230,7 +230,7 @@
"depends_on": "eval:doc.po_no",
"doctype": "DocField",
"fieldname": "po_date",
"fieldtype": "Data",
"fieldtype": "Date",
"hidden": 1,
"label": "Customer's Purchase Order Date",
"no_copy": 0,
@ -263,7 +263,6 @@
"reqd": 1
},
{
"default": "1.00",
"description": "Rate at which customer's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-21 16:16:39",
"docstatus": 0,
"modified": "2013-08-09 14:47:05",
"modified": "2013-10-11 13:20:13",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -215,7 +215,6 @@
"reqd": 1
},
{
"default": "1.00",
"description": "Rate at which supplier's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days
from webnotes.utils import cint, getdate, cstr, flt, add_days
import datetime
from webnotes import msgprint, _, ValidationError
@ -36,9 +36,8 @@ class DocType(StockController):
self.validate_amc_status()
self.validate_warehouse()
self.validate_item()
self.on_stock_ledger_entry()
def validate_amc_status(self):
"""
validate amc status
@ -115,7 +114,7 @@ class DocType(StockController):
and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""",
("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name,
self.doc.item_code), as_dict=1)
if purchase_sle:
self.doc.purchase_document_type = purchase_sle[0].voucher_type
self.doc.purchase_document_no = purchase_sle[0].voucher_no
@ -178,7 +177,7 @@ class DocType(StockController):
webnotes.conn.sql("""update `tab%s` set serial_no = %s
where name=%s""" % (dt[0], '%s', '%s'),
('\n'.join(serial_nos), item[0]))
def on_stock_ledger_entry(self):
if self.via_stock_ledger and not self.doc.fields.get("__islocal"):
self.set_status()

View File

@ -6,7 +6,7 @@ import webnotes
import webnotes.defaults
from webnotes.utils import cstr, cint, flt, comma_or, nowdate
from webnotes.model.doc import Document, addchild
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint, _
@ -20,6 +20,7 @@ class NotUpdateStockError(webnotes.ValidationError): pass
class StockOverReturnError(webnotes.ValidationError): pass
class IncorrectValuationRateError(webnotes.ValidationError): pass
class DuplicateEntryForProductionOrderError(webnotes.ValidationError): pass
class StockOverProductionError(webnotes.ValidationError): pass
from controllers.stock_controller import StockController
@ -54,13 +55,12 @@ class DocType(StockController):
from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
update_serial_nos_after_submit(self, "mtn_details")
self.update_production_order(1)
self.update_production_order()
self.make_gl_entries()
def on_cancel(self):
self.update_stock_ledger()
self.update_production_order(0)
self.update_production_order()
self.make_cancel_gl_entries()
def validate_fiscal_year(self):
@ -325,37 +325,44 @@ class DocType(StockController):
self.make_sl_entries(sl_entries, self.doc.amended_from and 'Yes' or 'No')
def update_production_order(self, is_submit):
def update_production_order(self):
def _validate_production_order(pro_bean):
if flt(pro_bean.doc.docstatus) != 1:
webnotes.throw(_("Production Order must be submitted") + ": " +
self.doc.production_order)
if pro_bean.doc.status == 'Stopped':
msgprint(_("Transaction not allowed against stopped Production Order") + ": " +
self.doc.production_order)
if self.doc.production_order:
# first perform some validations
# (they are here coz this fn is also called during on_cancel)
pro_obj = get_obj("Production Order", self.doc.production_order)
if flt(pro_obj.doc.docstatus) != 1:
msgprint("""You cannot do any transaction against
Production Order : %s, as it's not submitted"""
% (pro_obj.doc.name), raise_exception=1)
if pro_obj.doc.status == 'Stopped':
msgprint("""You cannot do any transaction against Production Order : %s,
as it's status is 'Stopped'"""% (pro_obj.doc.name), raise_exception=1)
# update bin
if self.doc.purpose == "Manufacture/Repack":
from stock.utils import update_bin
pro_obj.doc.produced_qty = flt(pro_obj.doc.produced_qty) + \
(is_submit and 1 or -1 ) * flt(self.doc.fg_completed_qty)
args = {
"item_code": pro_obj.doc.production_item,
"warehouse": pro_obj.doc.fg_warehouse,
"posting_date": self.doc.posting_date,
"planned_qty": (is_submit and -1 or 1 ) * flt(self.doc.fg_completed_qty)
}
update_bin(args)
pro_bean = webnotes.bean("Production Order", self.doc.production_order)
_validate_production_order(pro_bean)
self.update_produced_qty(pro_bean)
self.update_planned_qty(pro_bean)
# update production order status
pro_obj.doc.status = (flt(pro_obj.doc.qty)==flt(pro_obj.doc.produced_qty)) \
and 'Completed' or 'In Process'
pro_obj.doc.save()
def update_produced_qty(self, pro_bean):
if self.doc.purpose == "Manufacture/Repack":
produced_qty = flt(pro_bean.doc.produced_qty) + \
(self.doc.docstatus==1 and 1 or -1 ) * flt(self.doc.fg_completed_qty)
if produced_qty > flt(pro_bean.doc.qty):
webnotes.throw(_("Production Order") + ": " + self.doc.production_order + "\n" +
_("Total Manufactured Qty can not be greater than Planned qty to manufacture")
+ "(%s/%s)" % (produced_qty, flt(pro_bean.doc.qty)), StockOverProductionError)
status = 'Completed' if flt(produced_qty) >= flt(pro_bean.doc.qty) else 'In Process'
webnotes.conn.sql("""update `tabProduction Order` set status=%s, produced_qty=%s
where name=%s""", (status, produced_qty, self.doc.production_order))
def update_planned_qty(self, pro_bean):
from stock.utils import update_bin
update_bin({
"item_code": pro_bean.doc.production_item,
"warehouse": pro_bean.doc.fg_warehouse,
"posting_date": self.doc.posting_date,
"planned_qty": (self.doc.docstatus==1 and -1 or 1 ) * flt(self.doc.fg_completed_qty)
})
def get_item_details(self, arg):
arg = json.loads(arg)
@ -414,7 +421,8 @@ class DocType(StockController):
return ret
def get_items(self):
self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1)
self.doclist = filter(lambda d: d.parentfield!="mtn_details", self.doclist)
# self.doclist = self.doc.clear_table(self.doclist, 'mtn_details')
pro_obj = None
if self.doc.production_order:
@ -453,7 +461,7 @@ class DocType(StockController):
"stock_uom": pro_obj.doc.stock_uom
}
}, bom_no=pro_obj.doc.bom_no)
elif self.doc.purpose in ["Material Receipt", "Manufacture/Repack"]:
if self.doc.purpose=="Material Receipt":
self.doc.from_warehouse = ""
@ -470,6 +478,7 @@ class DocType(StockController):
}, bom_no=self.doc.bom_no)
self.get_stock_and_rate()
def get_bom_raw_materials(self, qty):
from manufacturing.doctype.bom.bom import get_bom_items_as_dict

View File

@ -3,8 +3,8 @@
from __future__ import unicode_literals
import webnotes
from webnotes import _, msgprint
from webnotes.utils import cint, flt, getdate, cstr
from webnotes import msgprint
from webnotes.utils import flt, getdate
from webnotes.model.controller import DocListController
class DocType(DocListController):

View File

@ -5,7 +5,6 @@ from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint, flt, validate_email_add
from webnotes.model.code import get_obj
from webnotes import msgprint, _
@ -91,103 +90,15 @@ class DocType:
webnotes.conn.delete_doc("Account", old_warehouse_account)
from utilities.repost_stock import repost
for item_code in items:
self.repost(item_code[0], self.doc.merge_with)
repost(item_code[0], self.doc.merge_with)
webnotes.conn.auto_commit_on_many_writes = 0
msgprint("Warehouse %s merged into %s. Now you can delete warehouse: %s"
% (self.doc.name, self.doc.merge_with, self.doc.name))
def repost(self, item_code, warehouse=None):
from stock.utils import get_bin
self.repost_actual_qty(item_code, warehouse)
bin = get_bin(item_code, warehouse)
self.repost_reserved_qty(bin)
self.repost_indented_qty(bin)
self.repost_ordered_qty(bin)
self.repost_planned_qty(bin)
bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.planned_qty) \
+ flt(bin.doc.indented_qty) + flt(bin.doc.ordered_qty) - flt(bin.doc.reserved_qty)
bin.doc.save()
def repost_actual_qty(self, item_code, warehouse=None):
from stock.stock_ledger import update_entries_after
if not warehouse:
warehouse = self.doc.name
update_entries_after({ "item_code": item_code, "warehouse": warehouse })
def repost_reserved_qty(self, bin):
reserved_qty = webnotes.conn.sql("""
select
sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
from
(
select
qty as dnpi_qty,
(
select qty from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_qty,
(
select ifnull(delivered_qty, 0) from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_delivered_qty
from
(
select qty, parent_detail_docname
from `tabDelivery Note Packing Item` dnpi_in
where item_code = %s and warehouse = %s
and parenttype="Sales Order"
and exists (select * from `tabSales Order` so
where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
) dnpi
) tab
where
so_item_qty >= so_item_delivered_qty
""", (bin.doc.item_code, bin.doc.warehouse))
if flt(bin.doc.reserved_qty) != flt(reserved_qty[0][0]):
webnotes.conn.set_value("Bin", bin.doc.name, "reserved_qty", flt(reserved_qty[0][0]))
def repost_indented_qty(self, bin):
indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty)
from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr
where pr_item.item_code=%s and pr_item.warehouse=%s
and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name
and pr.status!='Stopped' and pr.docstatus=1"""
, (bin.doc.item_code, bin.doc.warehouse))
if flt(bin.doc.indented_qty) != flt(indented_qty[0][0]):
webnotes.conn.set_value("Bin", bin.doc.name, "indented_qty", flt(indented_qty[0][0]))
def repost_ordered_qty(self, bin):
ordered_qty = webnotes.conn.sql("""
select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor)
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
where po_item.item_code=%s and po_item.warehouse=%s
and po_item.qty > po_item.received_qty and po_item.parent=po.name
and po.status!='Stopped' and po.docstatus=1"""
, (bin.doc.item_code, bin.doc.warehouse))
if flt(bin.doc.ordered_qty) != flt(ordered_qty[0][0]):
webnotes.conn.set_value("Bin", bin.doc.name, "ordered_qty", flt(ordered_qty[0][0]))
def repost_planned_qty(self, bin):
planned_qty = webnotes.conn.sql("""
select sum(qty - produced_qty) from `tabProduction Order`
where production_item = %s and fg_warehouse = %s and status != "Stopped"
and docstatus=1""", (bin.doc.item_code, bin.doc.warehouse))
if flt(bin.doc.planned_qty) != flt(planned_qty[0][0]):
webnotes.conn.set_value("Bin", bin.doc.name, "planned_qty", flt(planned_qty[0][0]))
def on_trash(self):
# delete bin
bins = webnotes.conn.sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1)
@ -209,4 +120,4 @@ class DocType:
msgprint("""Warehosue can not be deleted as stock ledger entry
exists for this warehouse.""", raise_exception=1)
else:
webnotes.conn.sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
webnotes.conn.sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)

View File

@ -209,7 +209,7 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters):
return wlist
def validate_warehouse_user(warehouse):
if webnotes.session.user=="Administrator":
if webnotes.session.user=="Administrator" or not warehouse:
return
warehouse_users = [p[0] for p in webnotes.conn.sql("""select user from `tabWarehouse User`
where parent=%s""", warehouse)]
@ -394,12 +394,3 @@ def notify_errors(exceptions_list):
from webnotes.profile import get_system_managers
sendmail(get_system_managers(), subject=subject, msg=msg)
def repost():
"""
Repost everything!
"""
from webnotes.model.code import get_obj
for wh in webnotes.conn.sql("select name from tabWarehouse"):
get_obj('Warehouse', wh[0]).repost_stock()

119
utilities/repost_stock.py Normal file
View File

@ -0,0 +1,119 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt
def repost():
"""
Repost everything!
"""
webnotes.conn.auto_commit_on_many_writes = 1
for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
repost_stock(d[0], d[1])
webnotes.conn.auto_commit_on_many_writes = 0
def repost_stock(item_code, warehouse):
repost_actual_qty(item_code, warehouse)
if item_code and warehouse:
update_bin(item_code, warehouse, {
"reserved_qty": get_reserved_qty(item_code, warehouse),
"indented_qty": get_indented_qty(item_code, warehouse),
"ordered_qty": get_ordered_qty(item_code, warehouse),
"planned_qty": get_planned_qty(item_code, warehouse)
})
def repost_actual_qty(item_code, warehouse):
from stock.stock_ledger import update_entries_after
update_entries_after({ "item_code": item_code, "warehouse": warehouse })
def get_reserved_qty(item_code, warehouse):
reserved_qty = webnotes.conn.sql("""
select
sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
from
(
(select
qty as dnpi_qty,
(
select qty from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_qty,
(
select ifnull(delivered_qty, 0) from `tabSales Order Item`
where name = dnpi.parent_detail_docname
) as so_item_delivered_qty,
parent, name
from
(
select qty, parent_detail_docname, parent, name
from `tabDelivery Note Packing Item` dnpi_in
where item_code = %s and warehouse = %s
and parenttype="Sales Order"
and item_code != parent_item
and exists (select * from `tabSales Order` so
where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
) dnpi)
union
(select qty as dnpi_qty, qty as so_item_qty,
ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
from `tabSales Order Item` so_item
where item_code = %s and reserved_warehouse = %s
and exists(select * from `tabSales Order` so
where so.name = so_item.parent and so.docstatus = 1
and so.status != 'Stopped'))
) tab
where
so_item_qty >= so_item_delivered_qty
""", (item_code, warehouse, item_code, warehouse))
return flt(reserved_qty[0][0]) if reserved_qty else 0
def get_indented_qty(item_code, warehouse):
indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0))
from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr
where pr_item.item_code=%s and pr_item.warehouse=%s
and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name
and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse))
return flt(indented_qty[0][0]) if indented_qty else 0
def get_ordered_qty(item_code, warehouse):
ordered_qty = webnotes.conn.sql("""
select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
where po_item.item_code=%s and po_item.warehouse=%s
and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
return flt(ordered_qty[0][0]) if ordered_qty else 0
def get_planned_qty(item_code, warehouse):
planned_qty = webnotes.conn.sql("""
select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order`
where production_item = %s and fg_warehouse = %s and status != "Stopped"
and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse))
return flt(planned_qty[0][0]) if planned_qty else 0
def update_bin(item_code, warehouse, qty_dict=None):
from stock.utils import get_bin
bin = get_bin(item_code, warehouse)
mismatch = False
for fld, val in qty_dict.items():
if flt(bin.doc.fields.get(fld)) != flt(val):
bin.doc.fields[fld] = flt(val)
mismatch = True
if mismatch:
bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.ordered_qty) + \
flt(bin.doc.indented_qty) + flt(bin.doc.planned_qty) - flt(bin.doc.reserved_qty)
bin.doc.save()

View File

@ -144,7 +144,6 @@ class TransactionBase(StatusUpdater):
def get_customer_address(self, args):
args = load_json(args)
webnotes.errprint(args)
ret = {
'customer_address' : args["address"],
'address_display' : get_address_display(args["address"]),
@ -432,14 +431,7 @@ def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, c
company_currency = webnotes.conn.get_value("Company", company, "default_currency")
# parenthesis for 'OR' are necessary as we want it to evaluate as
# mandatory valid condition and (1st optional valid condition
# or 2nd optional valid condition)
valid_conversion_rate = (conversion_rate and
((currency == company_currency and conversion_rate == 1.00)
or (currency != company_currency and conversion_rate != 1.00)))
if not valid_conversion_rate:
if not conversion_rate:
msgprint(_('Please enter valid ') + conversion_rate_label + (': ')
+ ("1 %s = [?] %s" % (currency, company_currency)),
raise_exception=True)