[Enhancement] POS

This commit is contained in:
Rohit Waghchaure 2016-04-09 14:31:09 +05:30
parent e00a20d99d
commit 6087fe178e
28 changed files with 2197 additions and 288 deletions

View File

@ -17,6 +17,7 @@
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Mode of Payment", "label": "Mode of Payment",
@ -26,6 +27,7 @@
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -33,6 +35,32 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Type",
"length": 0,
"no_copy": 0,
"options": "Cash\nBank\nGeneral",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -41,6 +69,7 @@
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Accounts", "label": "Accounts",
@ -50,6 +79,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -68,7 +98,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2015-11-16 06:29:50.335559", "modified": "2016-04-26 11:48:17.411796",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Mode of Payment", "name": "Mode of Payment",
@ -115,6 +145,9 @@
"write": 0 "write": 0
} }
], ],
"quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0 "read_only_onload": 0,
"sort_order": "ASC",
"track_seen": 0
} }

View File

@ -0,0 +1,191 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-05-08 23:49:38.842621",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Mode of Payment",
"length": 0,
"no_copy": 0,
"options": "Mode of Payment",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "0.0",
"depends_on": "eval:parent.doctype == 'Sales Invoice'",
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "2",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "type",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Type",
"length": 0,
"no_copy": 0,
"options": "mode_of_payment.type",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "base_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Amount (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-05-09 00:14:18.975568",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payments",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class Payments(Document):
pass

View File

@ -3,6 +3,7 @@
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"autoname": "hash", "autoname": "hash",
"beta": 0,
"creation": "2013-05-24 12:15:51", "creation": "2013-05-24 12:15:51",
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
@ -16,6 +17,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Applicable for User", "label": "Applicable for User",
@ -26,6 +28,7 @@
"options": "User", "options": "User",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -41,6 +44,7 @@
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Series", "label": "Series",
@ -51,6 +55,7 @@
"options": "[Select]", "options": "[Select]",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -58,31 +63,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -93,6 +73,7 @@
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Update Stock", "label": "Update Stock",
@ -100,6 +81,60 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "update_stock",
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Ignore Pricing Rule",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -115,6 +150,7 @@
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"length": 0, "length": 0,
@ -122,6 +158,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -137,6 +174,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Customer", "label": "Customer",
@ -147,6 +185,7 @@
"options": "Customer", "options": "Customer",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -162,6 +201,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Company", "label": "Company",
@ -172,6 +212,7 @@
"options": "Company", "options": "Company",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -187,6 +228,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Currency", "label": "Currency",
@ -197,6 +239,7 @@
"options": "Currency", "options": "Currency",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -208,19 +251,70 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"fieldname": "mode_of_payment", "fieldname": "allow_partial_payment",
"fieldtype": "Link", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Mode of Payment", "label": "Allow Partial Payment",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Mode of Payment",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payments",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payments",
"length": 0,
"no_copy": 0,
"options": "Payments",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -236,6 +330,7 @@
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"length": 0, "length": 0,
@ -243,6 +338,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -258,6 +354,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Print Format", "label": "Print Format",
@ -267,6 +364,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -282,6 +380,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Letter Head", "label": "Letter Head",
@ -292,6 +391,7 @@
"options": "Letter Head", "options": "Letter Head",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -307,6 +407,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Print Heading", "label": "Print Heading",
@ -317,6 +418,7 @@
"options": "Print Heading", "options": "Print Heading",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -332,6 +434,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Terms and Conditions", "label": "Terms and Conditions",
@ -342,6 +445,7 @@
"options": "Terms and Conditions", "options": "Terms and Conditions",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -357,6 +461,7 @@
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"length": 0, "length": 0,
@ -364,6 +469,33 @@
"oldfieldtype": "Column Break", "oldfieldtype": "Column Break",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Customer Group",
"length": 0,
"no_copy": 0,
"options": "Customer Group",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -380,6 +512,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Territory", "label": "Territory",
@ -390,6 +523,7 @@
"options": "Territory", "options": "Territory",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -405,6 +539,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Price List", "label": "Price List",
@ -415,6 +550,60 @@
"options": "Price List", "options": "Price List",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "apply_discount",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Apply Discount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Grand Total",
"depends_on": "apply_discount",
"fieldname": "apply_discount_on",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Apply Discount On",
"length": 0,
"no_copy": 0,
"options": "Grand Total\nNet Total",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -430,6 +619,7 @@
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"length": 0, "length": 0,
@ -437,6 +627,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -448,10 +639,12 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"depends_on": "",
"fieldname": "write_off_account", "fieldname": "write_off_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Write Off Account", "label": "Write Off Account",
@ -461,6 +654,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -476,6 +670,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Write Off Cost Center", "label": "Write Off Cost Center",
@ -485,6 +680,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -500,6 +696,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Taxes and Charges", "label": "Taxes and Charges",
@ -510,6 +707,7 @@
"options": "Sales Taxes and Charges Template", "options": "Sales Taxes and Charges Template",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -525,6 +723,7 @@
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"length": 0, "length": 0,
@ -532,6 +731,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -547,6 +747,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Cash/Bank Account", "label": "Cash/Bank Account",
@ -557,6 +758,7 @@
"options": "Account", "options": "Account",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -572,6 +774,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Income Account", "label": "Income Account",
@ -582,6 +785,7 @@
"options": "Account", "options": "Account",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -598,6 +802,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Expense Account", "label": "Expense Account",
@ -606,6 +811,7 @@
"options": "Account", "options": "Account",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -621,6 +827,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Cost Center", "label": "Cost Center",
@ -631,6 +838,7 @@
"options": "Cost Center", "options": "Cost Center",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -649,7 +857,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2015-11-16 06:29:51.741253", "modified": "2016-05-09 00:00:30.610878",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile", "name": "POS Profile",
@ -696,9 +904,11 @@
"write": 0 "write": 0
} }
], ],
"quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "user" "title_field": "user",
"track_seen": 0
} }

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import msgprint, _ from frappe import msgprint, _
from frappe.utils import cint from frappe.utils import cint
from erpnext.accounts.doctype.sales_invoice.sales_invoice import set_account_for_mode_of_payment
from frappe.model.document import Document from frappe.model.document import Document
@ -36,6 +37,9 @@ class POSProfile(Document):
"company": self.company, "name": link_dn}): "company": self.company, "name": link_dn}):
frappe.throw(_("{0} does not belong to Company {1}").format(link_dn, self.company)) frappe.throw(_("{0} does not belong to Company {1}").format(link_dn, self.company))
def before_save(self):
set_account_for_mode_of_payment(self)
def on_update(self): def on_update(self):
self.set_defaults() self.set_defaults()

View File

@ -129,7 +129,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
paid_amount: function() { paid_amount: function() {
this.set_in_company_currency(this.frm.doc, ["paid_amount"]); this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
this.write_off_outstanding_amount(); this.write_off_amount();
this.frm.refresh_fields(); this.frm.refresh_fields();
}, },

View File

@ -2,50 +2,186 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, json
from frappe import _
from frappe.utils import nowdate
from erpnext.setup.utils import get_exchange_rate
from erpnext.stock.get_item_details import get_pos_profile
from erpnext.controllers.accounts_controller import get_taxes_and_charges
@frappe.whitelist() @frappe.whitelist()
def get_items(price_list, sales_or_purchase, item=None): def get_pos_data():
condition = "" doc = frappe.new_doc('Sales Invoice')
order_by = "" doc.update_stock = 1;
args = {"price_list": price_list} doc.is_pos = 1;
pos_profile = get_pos_profile(doc.company)
if item: if not pos_profile:
# search serial no frappe.throw(_("Create pos profile first"))
item_code = frappe.db.sql("""select name as serial_no, item_code
from `tabSerial No` where name=%s""", (item), as_dict=1)
if item_code:
item_code[0]["name"] = item_code[0]["item_code"]
return item_code
# search barcode pos_profile = frappe.get_doc('POS Profile', pos_profile.name)
item_code = frappe.db.sql("""select name, item_code from `tabItem` update_pos_profile_data(doc, pos_profile)
where barcode=%s""", update_multi_mode_option(doc, pos_profile)
(item), as_dict=1)
if item_code:
item_code[0]["barcode"] = item
return item_code
condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))" return {
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999), 'doc': doc,
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999), 'items': get_items(doc, pos_profile),
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999), 'customers': get_customers(pos_profile),
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),""" 'pricing_rules': get_pricing_rules(doc),
args["name"] = "%%%s%%" % frappe.db.escape(item) 'mode_of_payment': get_mode_of_payment(doc),
args["_name"] = item.replace("%", "") 'print_template': frappe.db.get_value('Print Format', pos_profile.print_format, 'html') or '',
'meta': {
'invoice': frappe.get_meta('Sales Invoice'),
'items': frappe.get_meta('Sales Invoice Item'),
'taxes': frappe.get_meta('Sales Taxes and Charges')
}
}
# locate function is used to sort by closest match from the beginning of the value def update_pos_profile_data(doc, pos_profile):
return frappe.db.sql("""select i.name, i.item_name, i.image, company_data = frappe.db.get_value('Company', doc.company, '*', as_dict=1)
item_det.price_list_rate, item_det.currency
from `tabItem` i LEFT JOIN doc.taxes_and_charges = pos_profile.taxes_and_charges
(select item_code, price_list_rate, currency from if doc.taxes_and_charges:
`tabItem Price` where price_list=%(price_list)s) item_det update_tax_table(doc)
ON
(item_det.item_code=i.name or item_det.item_code=i.variant_of) doc.currency = pos_profile.currency or company_data.default_currency
where doc.conversion_rate = 1.0
i.has_variants = 0 and if doc.currency != company_data.default_currency:
{condition} doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency)
order by doc.selling_price_list = pos_profile.selling_price_list or frappe.db.get_value('Selling Settings', None, 'selling_price_list')
{order_by} doc.naming_series = pos_profile.naming_series or 'SINV-'
i.name doc.letter_head = pos_profile.letter_head or company_data.default_letter_head
limit 24""".format(condition=condition, order_by=order_by), args, as_dict=1) doc.ignore_pricing_rule = pos_profile.ignore_pricing_rule
doc.apply_discount_on = pos_profile.apply_discount_on
doc.customer_group = pos_profile.customer_group or get_root('Customer Group')
doc.territory = pos_profile.territory or get_root('Territory')
def get_root(table):
root = frappe.db.sql(""" select name from `tab%(table)s` having
min(lft)"""%{'table': table}, as_dict=1)
return root[0].name
def update_multi_mode_option(doc, pos_profile):
from frappe.model import default_fields
for payment_mode in pos_profile.payments:
payment_mode = payment_mode.as_dict()
for fieldname in default_fields:
if fieldname in payment_mode:
del payment_mode[fieldname]
doc.append('payments', payment_mode)
def update_tax_table(doc):
taxes = get_taxes_and_charges('Sales Taxes and Charges Template', doc.taxes_and_charges)
for tax in taxes:
doc.append('taxes', tax)
def get_items(doc, pos_profile):
item_list = []
for item in frappe.get_all("Item", fields=["*"], filters={'disabled': 0, 'has_variants': 0}):
item_doc = frappe.get_doc('Item', item.name)
if item_doc.taxes:
item.taxes = json.dumps(dict(([d.tax_type, d.tax_rate] for d in
item_doc.get("taxes"))))
item.price_list_rate = frappe.db.get_value('Item Price', {'item_code': item.name,
'price_list': doc.selling_price_list}, 'price_list_rate') or 0
item.default_warehouse = pos_profile.warehouse or item.default_warehouse or None
item.expense_account = pos_profile.expense_account or item.expense_account
item.income_account = pos_profile.income_account or item_doc.income_account
item.cost_center = pos_profile.cost_center or item_doc.selling_cost_center
item.actual_qty = frappe.db.get_value('Bin', {'item_code': item.name,
'warehouse': item.default_warehouse}, 'actual_qty') or 0
item.serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where warehouse= %(warehouse)s
and item_code = %(item_code)s""", {'warehouse': item.default_warehouse, 'item_code': item.item_code})
item_list.append(item)
return item_list
def get_customers(pos_profile):
filters = {'disabled': 0}
if pos_profile.customer:
filters.update({'name': pos_profile.customer})
return frappe.get_all("Customer", fields=["*"], filters = filters)
def get_pricing_rules(doc):
if doc.ignore_pricing_rule == 0:
return frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 and disable = 0
and selling = 1 and ifnull(company, '') in (%(company)s, '') and
ifnull(for_price_list, '') in (%(price_list)s, '') and %(date)s between
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') order by priority desc, name desc""",
{'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1)
def get_mode_of_payment(doc):
return frappe.get_all('Mode of Payment Account', fields = ['distinct parent'], filters={'company': doc.company})
@frappe.whitelist()
def make_invoice(doc_list):
if isinstance(doc_list, basestring):
doc_list = json.loads(doc_list)
name_list = []
for docs in doc_list:
for name, doc in docs.items():
validate_customer(doc)
validate_item(doc)
si_doc = frappe.new_doc('Sales Invoice')
si_doc.offline_pos_name = name
si_doc.update(doc)
submit_invoice(si_doc)
name_list.append(name)
return name_list
def validate_customer(doc):
if not frappe.db.get_value('Customer', doc.get('customer')):
customer_doc = frappe.new_doc('Customer')
customer_doc.customer_name = doc.get('customer')
customer_doc.customer_type = 'Company'
customer_doc.customer_group = doc.get('customer_group')
customer_doc.territory = doc.get('territory')
customer_doc.save(ignore_permissions = True)
frappe.db.commit()
doc['customer'] = customer_doc.name
return doc
def validate_item(doc):
for item in doc.get('items'):
if not frappe.db.exists('Item', item.get('item_code')):
item_doc = frappe.new_doc('Item')
item_doc.name = item.get('item_code')
item_doc.item_code = item.get('item_code')
item_doc.item_name = item.get('item_name')
item_doc.description = item.get('description')
item_doc.default_warehouse = item.get('warehouse')
item_doc.stock_uom = item.get('stock_uom')
item_doc.item_group = item.get('item_group')
item_doc.save(ignore_permissions=True)
frappe.db.commit()
def submit_invoice(si_doc):
try:
si_doc.insert()
si_doc.submit()
except Exception, e:
if frappe.message_log: frappe.message_log.pop()
frappe.db.rollback()
save_invoice(e, si_doc)
def save_invoice(e, si_doc):
si_doc.docstatus = 0
si_doc.name = ''
si_doc.save(ignore_permissions=True)
make_scheduler_log(e, si_doc.name)
def make_scheduler_log(e, sales_invoice):
scheduler_log = frappe.new_doc('Scheduler Log')
scheduler_log.error = e
scheduler_log.sales_invoice = sales_invoice
scheduler_log.save(ignore_permissions=True)

View File

@ -17,17 +17,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.frm.set_df_property("debit_to", "print_hide", 0); this.frm.set_df_property("debit_to", "print_hide", 0);
} }
// toggle to pos view if is_pos is 1 in user_defaults
if ((is_null(this.frm.doc.is_pos) && cint(frappe.defaults.get_user_default("is_pos"))===1) || this.frm.doc.is_pos) {
if(this.frm.doc.__islocal && !this.frm.doc.amended_from && !this.frm.doc.customer) {
this.frm.set_value("is_pos", 1);
this.is_pos(function() {
if (cint(frappe.defaults.get_user_defaults("fs_pos_view"))===1)
erpnext.pos.toggle(me.frm, true);
});
}
}
erpnext.queries.setup_queries(this.frm, "Warehouse", function() { erpnext.queries.setup_queries(this.frm, "Warehouse", function() {
return erpnext.queries.warehouse(me.frm.doc); return erpnext.queries.warehouse(me.frm.doc);
}); });
@ -149,39 +138,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.get_terms(); this.get_terms();
}, },
is_pos: function(doc, dt, dn, callback_fn) {
cur_frm.cscript.hide_fields(this.frm.doc);
if(cur_frm.doc.__missing_values_set) return;
if(cint(this.frm.doc.is_pos)) {
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
msgprint(__("Please specify Company to proceed"));
} else {
var me = this;
return this.frm.call({
doc: me.frm.doc,
method: "set_missing_values",
callback: function(r) {
if(!r.exc) {
if(r.message && r.message.print_format) {
cur_frm.pos_print_format = r.message.print_format;
}
cur_frm.doc.__missing_values_set = true;
me.frm.script_manager.trigger("update_stock");
frappe.model.set_default_values(me.frm.doc);
me.set_dynamic_labels();
me.calculate_taxes_and_totals();
if(callback_fn) callback_fn();
frappe.after_ajax(function() {
cur_frm.doc.__missing_values_set = false;
})
}
}
});
}
}
},
customer: function() { customer: function() {
var me = this; var me = this;
if(this.frm.updating_party_details) return; if(this.frm.updating_party_details) return;
@ -245,11 +201,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.write_off_outstanding_amount_automatically(); this.write_off_outstanding_amount_automatically();
}, },
paid_amount: function() {
this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
this.write_off_outstanding_amount_automatically();
},
items_add: function(doc, cdt, cdn) { items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]); this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);

View File

@ -3,6 +3,7 @@
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 0,
"autoname": "naming_series:", "autoname": "naming_series:",
"beta": 0,
"creation": "2013-05-24 19:29:05", "creation": "2013-05-24 19:29:05",
"custom": 0, "custom": 0,
"default_print_format": "Standard", "default_print_format": "Standard",
@ -194,6 +195,31 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "offline_pos_name",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Offline POS Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -653,6 +679,32 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "territory",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Territory",
"length": 0,
"no_copy": 0,
"options": "Territory",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -1941,7 +1993,7 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "paid_amount", "collapsible_depends_on": "",
"depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)", "depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)",
"fieldname": "payments_section", "fieldname": "payments_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@ -1971,7 +2023,7 @@
"depends_on": "is_pos", "depends_on": "is_pos",
"fieldname": "cash_bank_account", "fieldname": "cash_bank_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 1,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
@ -1996,9 +2048,34 @@
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"depends_on": "is_pos", "fieldname": "payments",
"fieldname": "column_break3", "fieldtype": "Table",
"fieldtype": "Column Break", "hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payments",
"length": 0,
"no_copy": 0,
"options": "Payments",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_84",
"fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -2007,6 +2084,7 @@
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
@ -2014,35 +2092,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"unique": 0,
"width": "50%"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "is_pos",
"fieldname": "paid_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Paid Amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "paid_amount",
"oldfieldtype": "Currency",
"options": "currency",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -2071,6 +2120,110 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "base_change_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Change Amount (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_86",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "is_pos",
"fieldname": "paid_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Paid Amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "paid_amount",
"oldfieldtype": "Currency",
"options": "currency",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "change_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Change Amount",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -3443,7 +3596,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2016-04-14 13:01:01.748816", "modified": "2016-05-09 15:03:33.236351",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",
@ -3530,6 +3683,7 @@
"write": 0 "write": 0
} }
], ],
"quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 1, "read_only_onload": 1,
"search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount", "search_fields": "posting_date, due_date, customer, base_grand_total, outstanding_amount",

View File

@ -64,8 +64,8 @@ class SalesInvoice(SellingController):
self.validate_fixed_asset() self.validate_fixed_asset()
self.set_income_account_for_fixed_assets() self.set_income_account_for_fixed_assets()
if cint(self.is_pos): # if cint(self.is_pos):
self.validate_pos() # self.validate_pos()
if cint(self.update_stock): if cint(self.update_stock):
self.validate_dropship_item() self.validate_dropship_item()
@ -83,6 +83,18 @@ class SalesInvoice(SellingController):
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items") self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
self.update_packing_list() self.update_packing_list()
def before_save(self):
set_account_for_mode_of_payment(self)
def update_change_amount(self):
self.base_paid_amount = 0.0
if self.paid_amount:
self.base_paid_amount = flt(self.paid_amount * self.conversion_rate, self.precision("base_paid_amount"))
self.change_amount = self.base_change_amount = 0.0
if self.paid_amount > self.grand_total:
self.change_amount = flt(self.paid_amount - self.grand_total, self.precision("change_amount"))
self.base_change_amount = flt(self.change_amount * self.conversion_rate, self.precision("base_change_amount"))
def on_submit(self): def on_submit(self):
if not self.recurring_id: if not self.recurring_id:
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
@ -588,8 +600,7 @@ class SalesInvoice(SellingController):
gl_entries += super(SalesInvoice, self).get_gl_entries() gl_entries += super(SalesInvoice, self).get_gl_entries()
def make_pos_gl_entries(self, gl_entries): def make_pos_gl_entries(self, gl_entries):
if cint(self.is_pos) and self.cash_bank_account and self.paid_amount: if cint(self.is_pos) and self.paid_amount:
bank_account_currency = get_account_currency(self.cash_bank_account)
# POS, make payment entries # POS, make payment entries
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
@ -597,21 +608,42 @@ class SalesInvoice(SellingController):
"party_type": "Customer", "party_type": "Customer",
"party": self.customer, "party": self.customer,
"against": self.cash_bank_account, "against": self.cash_bank_account,
"credit": self.base_paid_amount, "credit": flt(self.base_paid_amount - self.base_change_amount),
"credit_in_account_currency": self.base_paid_amount \ "credit_in_account_currency": flt(self.base_paid_amount - self.base_change_amount) \
if self.party_account_currency==self.company_currency else self.paid_amount, if self.party_account_currency==self.company_currency else flt(self.paid_amount - self.change_amount),
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,
}, self.party_account_currency) }, self.party_account_currency)
) )
cash_account = ''
for payment_mode in self.payments:
if payment_mode.type == 'Cash':
cash_account = payment_mode.account
if payment_mode.base_amount > 0:
payment_mode_account_currency = get_account_currency(payment_mode.account)
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.cash_bank_account, "account": payment_mode.account,
"against": self.customer, "against": self.customer,
"debit": self.base_paid_amount, "debit": payment_mode.base_amount,
"debit_in_account_currency": self.base_paid_amount \ "debit_in_account_currency": payment_mode.base_amount \
if bank_account_currency==self.company_currency else self.paid_amount if payment_mode_account_currency==self.company_currency else payment_mode.amount
}, bank_account_currency) }, payment_mode_account_currency)
)
if self.change_amount:
cash_account = cash_account or self.payments[0].account
cash_account_currency = get_account_currency(cash_account)
gl_entries.append(
self.get_gl_dict({
"account": cash_account,
"against": self.customer,
"credit": self.base_change_amount,
"credit_in_account_currency": self.base_change_amount \
if payment_mode_account_currency==self.company_currency else self.change_amount
}, payment_mode_account_currency)
) )
def make_write_off_gl_entry(self, gl_entries): def make_write_off_gl_entry(self, gl_entries):
@ -680,7 +712,7 @@ def get_bank_cash_account(mode_of_payment, company):
account = frappe.db.get_value("Mode of Payment Account", account = frappe.db.get_value("Mode of Payment Account",
{"parent": mode_of_payment, "company": company}, "default_account") {"parent": mode_of_payment, "company": company}, "default_account")
if not account: if not account:
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment)) frappe.throw(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
return { return {
"account": account "account": account
} }
@ -738,3 +770,8 @@ def make_delivery_note(source_name, target_doc=None):
def make_sales_return(source_name, target_doc=None): def make_sales_return(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Sales Invoice", source_name, target_doc) return make_return_doc("Sales Invoice", source_name, target_doc)
def set_account_for_mode_of_payment(self):
for data in self.payments:
if not data.account:
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")

View File

@ -441,17 +441,45 @@ class TestSalesInvoice(unittest.TestCase):
self.make_pos_profile() self.make_pos_profile()
self._insert_purchase_receipt() self._insert_purchase_receipt()
pos = copy.deepcopy(test_records[1]) pos = copy.deepcopy(test_records[1])
pos["is_pos"] = 1 pos["is_pos"] = 1
pos["update_stock"] = 1 pos["update_stock"] = 1
pos["cash_bank_account"] = "_Test Bank - _TC" pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
pos["paid_amount"] = 600.0 {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300}]
si = frappe.copy_doc(pos) si = frappe.copy_doc(pos)
si.insert() si.insert()
si.submit() si.submit()
self.assertEquals(si.paid_amount, 600.0)
self.pos_gl_entry(si, pos, 300)
def test_make_pos_invoice(self):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
set_perpetual_inventory()
self.make_pos_profile()
self._insert_purchase_receipt()
pos = copy.deepcopy(test_records[1])
pos["is_pos"] = 1
pos["update_stock"] = 1
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
invoice_data = [{'09052016142': pos}]
si = make_invoice(invoice_data)
self.assertEquals(si[0], '09052016142')
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1})
si = frappe.get_doc('Sales Invoice', sales_invoice[0].name)
self.assertEquals(si.grand_total, 630.0)
self.pos_gl_entry(si, pos, 330)
def pos_gl_entry(self, si, pos, cash_amount):
# check stock ledger entries # check stock ledger entries
sle = frappe.db.sql("""select * from `tabStock Ledger Entry` sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
where voucher_type = 'Sales Invoice' and voucher_no = %s""", where voucher_type = 'Sales Invoice' and voucher_no = %s""",
@ -475,8 +503,9 @@ class TestSalesInvoice(unittest.TestCase):
[pos["taxes"][1]["account_head"], 0.0, 50.0], [pos["taxes"][1]["account_head"], 0.0, 50.0],
[stock_in_hand, 0.0, abs(sle.stock_value_difference)], [stock_in_hand, 0.0, abs(sle.stock_value_difference)],
[pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0], [pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
[si.debit_to, 0.0, 600.0], [si.debit_to, 0.0, si.paid_amount],
["_Test Bank - _TC", 600.0, 0.0] ["_Test Bank - _TC", 300.0, 0.0],
["Cash - _TC", cash_amount, 0.0]
]) ])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)): for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):

View File

@ -1,46 +1,843 @@
frappe.provide("erpnext.pos");
{% include "erpnext/public/js/controllers/taxes_and_totals.js" %}
frappe.pages['pos'].on_page_load = function(wrapper) { frappe.pages['pos'].on_page_load = function(wrapper) {
var page = frappe.ui.make_app_page({ var page = frappe.ui.make_app_page({
parent: wrapper, parent: wrapper,
title: __('Start Point-of-Sale (POS)'), title: 'Point of Sale',
single_column: true single_column: true
}); });
page.main.html(frappe.render_template("pos_page", {})); wrapper = $(wrapper).find('.page-content')
new erpnext.pos.PointOfSale(page, wrapper)
}
var pos_type = frappe.ui.form.make_control({ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
parent: page.main.find(".select-type"), init: function(page, wrapper){
df: { this.page = page;
fieldtype: "Select", this.wrapper = wrapper;
options: [ this.set_indicator();
{label: __("Billing (Sales Invoice)"), value:"Sales Invoice"}, this.onload();
{value:"Sales Order"}, this.make_menu_list();
{value:"Delivery Note"}, this.set_interval_for_si_sync();
{value:"Quotation"}, this.si_docs = this.get_doc_from_localstorage();
{value:"Purchase Order"},
{value:"Purchase Receipt"},
{value:"Purchase Invoice"},
],
fieldname: "pos_type"
}, },
only_input: true
});
pos_type.refresh(); check_internet_connection: function(){
var me = this;
//Check Internet connection after every 30 seconds
setInterval(function(){
me.set_indicator();
}, 30000)
},
pos_type.set_input("Sales Invoice"); set_indicator: function(){
var me = this;
page.main.find(".btn-primary").on("click", function() { // navigator.onLine
erpnext.open_as_pos = true; this.page.set_indicator("Offline", "grey")
new_doc(pos_type.get_value()); frappe.call({
}); method:"frappe.handler.ping",
callback: function(r){
$.ajax({ if(r.message){
url: "/api/resource/POS Profile", me.connection_status = true;
success: function(data) { me.page.set_indicator("Online", "green")
if(!data.data.length) {
page.main.find(".pos-setting-message").removeClass('hide');
} }
} }
}) })
},
onload: function(){
var me = this;
this.get_data_from_server(function(){
me.create_new();
});
this.check_internet_connection();
},
make_menu_list: function(){
var me = this;
this.page.add_menu_item(__("Unsync Records"), function(){
me.show_unsync_invoice_list()
});
this.page.add_menu_item(__("Sync Master Data"), function(){
me.get_data_from_server()
});
this.page.add_menu_item(__("New Sales Invoice"), function() {
me.create_new()
})
},
show_unsync_invoice_list: function(){
var me = this;
this.si_docs = this.get_doc_from_localstorage();
this.list_dialog = new frappe.ui.Dialog({
title: 'Invoice List'
});
this.list_dialog.show();
this.list_body = this.list_dialog.body;
$(this.list_body).append('<div class="row list-row list-row-head pos-invoice-list">\
<div class="col-xs-6">Customer</div>\
<div class="col-xs-3 text-right">Grand Total</div>\
<div class="col-xs-3 text-right">Status</div>\
</div>')
$.each(this.si_docs, function(index, data){
for(key in data) {
$(frappe.render_template("pos_invoice_list", {
name: key,
customer: data[key].customer,
grand_total: data[key].grand_total,
status: (data[key].docstatus == 1) ? 'Submitted' : 'Draft'
})).appendTo($(me.list_body));
} }
})
$(this.list_body).find('.list-row').click(function() {
me.name = $(this).attr('invoice-name')
doc_data = me.get_invoice_doc(me.si_docs)
if(doc_data){
me.frm.doc = doc_data[0][me.name];
me.refresh();
me.disable_input_field();
me.list_dialog.hide();
}
})
},
get_invoice_doc: function(si_docs){
var me = this;
this.si_docs = this.get_doc_from_localstorage();
return $.grep(this.si_docs, function(data){
for(key in data){
return key == me.name
}
})
},
get_data_from_server: function(callback){
var me = this;
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.pos.get_pos_data",
freeze: true,
callback: function(r){
window.items = r.message.items;
window.customers = r.message.customers;
window.pricing_rules = r.message.pricing_rules;
window.meta = r.message.meta;
window.print_template = r.message.print_template;
localStorage.setItem('doc', JSON.stringify(r.message.doc));
if(callback){
callback();
}
}
})
},
create_new: function(){
this.frm = {}
var me = this;
this.name = '';
this.frm.doc = JSON.parse(localStorage.getItem('doc'))
this.load_data();
this.setup();
},
load_data: function(){
this.items = window.items;
this.customers = window.customers;
this.pricing_rules = window.pricing_rules;
$.each(window.meta, function(i, data){
frappe.meta.sync(data)
})
this.print_template = frappe.render_template("print_template",
{content: window.print_template, title:"POS"})
},
setup: function(){
this.wrapper.html(frappe.render_template("pos", this.frm.doc));
this.set_transaction_defaults("Customer");
this.make();
this.set_primary_action();
},
set_transaction_defaults: function(party) {
var me = this;
this.party = party;
this.price_list = (party == "Customer" ?
this.frm.doc.selling_price_list : this.frm.doc.buying_price_list);
this.price_list_field = (party == "Customer" ? "selling_price_list" : "buying_price_list");
this.sales_or_purchase = (party == "Customer" ? "Sales" : "Purchase");
},
make: function() {
this.make_search();
this.make_customer();
this.make_item_list();
this.make_discount_field()
},
make_search: function() {
var me = this;
this.search = frappe.ui.form.make_control({
df: {
"fieldtype": "Data",
"label": "Item",
"fieldname": "pos_item",
"placeholder": "Search Item"
},
parent: this.wrapper.find(".search-area"),
only_input: true,
});
this.search.make_input();
this.search.$input.on("keyup", function() {
setTimeout(function() {
me.items = me.get_items();
me.make_item_list();
}, 1000);
});
this.party_field = frappe.ui.form.make_control({
df: {
"fieldtype": "Data",
"options": this.party,
"label": this.party,
"fieldname": this.party.toLowerCase(),
"placeholder": this.party
},
parent: this.wrapper.find(".party-area"),
only_input: true,
});
this.party_field.make_input();
},
make_customer: function() {
var me = this;
if(this.customers.length == 1){
this.party_field.$input.val(this.customers[0].name);
this.frm.doc.customer = this.customers[0].name;
}
this.party_field.$input.autocomplete({
source: function (request, response) {
me.customer_data = me.get_customers(request.term)
response($.map(me.customer_data, function(data){
return {label: data.name, value: data.name,
customer_group: data.customer_group, territory: data.territory}
}))
},
change: function(event, ui){
if(ui.item){
me.frm.doc.customer = ui.item.label;
me.frm.doc.customer_name = ui.item.customer_name;
me.frm.doc.customer_group = ui.item.customer_group;
me.frm.doc.territory = ui.item.territory;
}else{
me.frm.doc.customer = me.party_field.$input.val();
}
me.refresh();
}
})
},
get_customers: function(key){
var me = this;
key = key.toLowerCase()
return $.grep(this.customers, function(data) {
if(data.name.toLowerCase().match(key) || data.customer_name.toLowerCase().match(key)
|| data.customer_group.toLowerCase().match(key)){
return data
}
})
},
make_item_list: function() {
var me = this;
if(!this.price_list) {
msgprint(__("Price List not found or disabled"));
return;
}
me.item_timeout = null;
var $wrap = me.wrapper.find(".item-list");
me.wrapper.find(".item-list").empty();
if (this.items) {
$.each(this.items, function(index, obj) {
if(index < 16){
$(frappe.render_template("pos_item", {
item_code: obj.name,
item_price: format_currency(obj.price_list_rate, obj.currency),
item_name: obj.name===obj.item_name ? "" : obj.item_name,
item_image: obj.image ? "url('" + obj.image + "')" : null,
color: frappe.get_palette(obj.item_name),
abbr: frappe.get_abbr(obj.item_name)
})).tooltip().appendTo($wrap);
}
});
}
if(this.items.length == 1){
this.search.$input.val("");
this.add_to_cart();
}
// if form is local then allow this function
$(me.wrapper).find("div.pos-item").on("click", function() {
me.customer_validate();
if(me.frm.doc.docstatus==0) {
me.items = me.get_items($(this).attr("data-item-code"))
me.add_to_cart();
}
});
},
get_items: function(item_code){
// To search item as per the key enter
var me = this;
this.item_serial_no = {}
if(item_code){
return $.grep(window.items, function(item){
if(item.item_code == item_code ){
return true
}
})
}
key = this.search.$input.val().toLowerCase();
if(key){
return $.grep(window.items, function(item){
if( (item.item_code.toLowerCase().match(key)) ||
(item.item_name.toLowerCase().match(key)) || (item.item_group.toLowerCase().match(key)) ){
return true
}else if(item.barcode){
return item.barcode == me.search.$input.val()
} else if (in_list(item.serial_nos, me.search.$input.val())){
me.item_serial_no[item.item_code] = me.search.$input.val()
return true
}
})
}else{
return window.items;
}
},
update_qty: function() {
var me = this;
$(this.wrapper).find(".pos-item-qty").on("change", function(){
var item_code = $(this).parents(".pos-bill-item").attr("data-item-code");
me.update_qty_against_item_code(item_code, $(this).val());
})
$(this.wrapper).find("[data-action='increase-qty']").on("click", function(){
var item_code = $(this).parents(".pos-bill-item").attr("data-item-code");
var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) + 1;
me.update_qty_against_item_code(item_code, qty);
})
$(this.wrapper).find("[data-action='decrease-qty']").on("click", function(){
var item_code = $(this).parents(".pos-bill-item").attr("data-item-code");
var qty = flt($(this).parents(".pos-bill-item").find('.pos-item-qty').val()) - 1;
me.update_qty_against_item_code(item_code, qty);
})
},
update_qty_against_item_code: function(item_code, qty){
var me = this;
if(qty < 0){
frappe.throw(__("Quantity must be positive"));
}
this.remove_item = []
$.each(this.frm.doc["items"] || [], function(i, d) {
if (d.item_code == item_code) {
d.qty = flt(qty);
d.amount = flt(d.rate) * flt(d.qty);
if(d.qty==0){
me.remove_item.push(d.idx)
}
}
});
this.remove_zero_qty_item();
this.refresh();
},
remove_zero_qty_item: function(){
var me = this;
idx = 0
this.items = []
idx = 0
$.each(this.frm.doc["items"] || [], function(i, d) {
if(!in_list(me.remove_item, d.idx)){
d.idx = idx;
me.items.push(d);
idx++;
}
});
this.frm.doc["items"] = this.items;
},
make_discount_field: function(){
var me = this;
this.wrapper.find('input.discount-percentage').on("change", function() {
me.frm.doc.additional_discount_percentage = flt($(this).val(), precision("additional_discount_percentage"));
total = me.frm.doc.grand_total
if(me.frm.doc.apply_discount_on == 'Net Total'){
total = me.frm.doc.net_total
}
me.frm.doc.discount_amount = flt(total*flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount"));
me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount)
me.refresh();
});
this.wrapper.find('input.discount-amount').on("change", function() {
me.frm.doc.discount_amount = flt($(this).val(), precision("discount_amount"));
me.frm.doc.additional_discount_percentage = 0.0;
me.wrapper.find('input.discount-percentage').val(0);
me.refresh();
});
},
customer_validate: function(){
var me = this;
if(!this.frm.doc.customer){
frappe.throw(__("Please select customer"))
}
},
add_to_cart: function() {
var me = this;
var caught = false;
var no_of_items = me.wrapper.find(".pos-bill-item").length;
this.validate_serial_no()
this.validate_warehouse();
if (no_of_items != 0) {
$.each(this.frm.doc["items"] || [], function(i, d) {
if (d.item_code == me.items[0].item_code) {
caught = true;
d.qty += 1;
d.amount = flt(d.rate) * flt(d.qty)
if(me.item_serial_no.length){
d.serial_no += '\n' + me.item_serial_no[d.item_code]
}
}
});
}
// if item not found then add new item
if (!caught)
this.add_new_item_to_grid();
this.refresh();
},
add_new_item_to_grid: function() {
var me = this;
this.child = frappe.model.add_child(this.frm.doc, this.frm.doc.doctype + " Item", "items");
this.child.item_code = this.items[0].item_code;
this.child.item_name = this.items[0].item_name;
this.child.stock_uom = this.items[0].stock_uom;
this.child.description = this.items[0].description;
this.child.qty = 1;
this.child.item_group = this.items[0].item_group;
this.child.cost_center = this.items[0].cost_center;
this.child.income_account = this.items[0].income_account;
this.child.warehouse = this.items[0].default_warehouse;
this.child.price_list_rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
this.child.rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
this.child.actual_qty = this.items[0].actual_qty;
this.child.amount = flt(this.child.qty) * flt(this.child.rate);
this.child.serial_no = this.item_serial_no[this.child.item_code];
},
refresh: function() {
var me = this;
this.refresh_fields();
this.update_qty();
this.set_primary_action();
},
refresh_fields: function() {
this.apply_pricing_rule();
this.discount_amount_applied = false;
this._calculate_taxes_and_totals();
this.calculate_discount_amount();
this.show_items_in_item_cart();
this.set_taxes();
this.calculate_outstanding_amount();
this.set_totals();
},
get_company_currency: function() {
return erpnext.get_currency(this.frm.doc.company);
},
show_item_wise_taxes: function(){
return null;
},
show_items_in_item_cart: function() {
var me = this;
var $items = this.wrapper.find(".items").empty();
me.frm.doc.net_total = 0.0
$.each(this.frm.doc.items|| [], function(i, d) {
$(frappe.render_template("pos_bill_item", {
item_code: d.item_code,
item_name: (d.item_name===d.item_code || !d.item_name) ? "" : ("<br>" + d.item_name),
qty: d.qty,
actual_qty: d.actual_qty,
projected_qty: d.projected_qty,
rate: format_currency(d.rate, me.frm.doc.currency),
amount: format_currency(d.amount, me.frm.doc.currency)
})).appendTo($items);
});
this.wrapper.find("input.pos-item-qty").on("focus", function() {
$(this).select();
});
},
set_taxes: function(){
var me = this;
me.frm.doc.total_taxes_and_charges = 0.0
var taxes = this.frm.doc.taxes || [];
$(this.wrapper)
.find(".tax-area").toggleClass("hide", (taxes && taxes.length) ? false : true)
.find(".tax-table").empty();
$.each(taxes, function(i, d) {
if (d.tax_amount && cint(d.included_in_print_rate) == 0) {
$(frappe.render_template("pos_tax_row", {
description: d.description,
tax_amount: format_currency(flt(d.tax_amount_after_discount_amount),
me.frm.doc.currency)
})).appendTo(me.wrapper.find(".tax-table"));
}
});
},
set_totals: function() {
var me = this;
this.wrapper.find(".net-total").text(format_currency(me.frm.doc.total, me.frm.doc.currency));
this.wrapper.find(".grand-total").text(format_currency(me.frm.doc.grand_total, me.frm.doc.currency));
},
set_primary_action: function() {
var me = this;
if (this.frm.doc.docstatus==0 && this.frm.doc.outstanding_amount > 0) {
this.page.set_primary_action(__("Pay"), function() {
me.validate()
me.create_invoice();
me.make_payment();
});
}else if(this.frm.doc.docstatus == 0){
this.page.set_primary_action(__("Submit"), function() {
frappe.confirm(__("Do you really want to submit the invoice?"), function () {
me.write_off_amount()
})
})
}else if(this.frm.doc.docstatus == 1){
this.page.set_primary_action(__("Print"), function() {
html = frappe.render(me.print_template, me.frm.doc)
frappe.require("/assets/js/print_format_v3.min.js", function() {
w = _p.preview(html);
setTimeout(function(){
w.print();
}, 1000)
});
})
}
},
write_off_amount: function(){
var me = this;
var value = 0.0;
if(this.frm.doc.outstanding_amount > 0){
dialog = new frappe.ui.Dialog({
title: 'Write Off Amount',
fields: [
{fieldtype: "Currency", fieldname: "write_off_amount", label: __("Amount"), reqd: 1},
]
});
dialog.show();
dialog.fields_dict.write_off_amount.$input.change(function(){
value = dialog.get_values()
})
dialog.set_primary_action(__("Submit"), function(){
me.frm.doc.write_off_amount = value.write_off_amount;
me.calculate_outstanding_amount();
dialog.hide();
me.change_status();
})
}else{
me.change_status();
}
},
change_status: function(){
if(this.frm.doc.docstatus == 0){
this.frm.doc.docstatus = 1;
this.update_invoice();
this.disable_input_field();
}
},
disable_input_field: function(){
var pointer_events = 'inherit'
$(this.wrapper).find('input').attr("disabled", false);
if(this.frm.doc.docstatus == 1){
pointer_events = 'none'
$(this.wrapper).find('input').attr("disabled", true);
}
$(this.wrapper).find('.pos-bill-wrapper').css('pointer-events', pointer_events);
$(this.wrapper).find('.pos-items-section').css('pointer-events', pointer_events);
this.set_primary_action();
},
create_invoice: function(){
var me = this;
var invoice_data = {}
this.si_docs = this.get_doc_from_localstorage();
if(this.name){
this.update_invoice()
}else{
this.name = $.now();
invoice_data[this.name] = this.frm.doc
this.si_docs.push(invoice_data)
this.update_localstorage();
this.set_primary_action();
}
},
update_invoice: function(){
var me = this;
this.si_docs = this.get_doc_from_localstorage();
$.each(this.si_docs, function(index, data){
for(key in data){
if(key == me.name){
me.si_docs[index][key] = me.frm.doc
me.update_localstorage();
}
}
})
},
update_localstorage: function(){
try{
localStorage.setItem('sales_invoice_doc', JSON.stringify(this.si_docs));
}catch(e){
frappe.throw(__("LocalStorage is full , did not save"))
}
},
get_doc_from_localstorage: function(){
return JSON.parse(localStorage.getItem('sales_invoice_doc')) || [];
},
set_interval_for_si_sync: function(){
var me = this;
setInterval(function(){
me.sync_sales_invoice()
}, 6000)
},
sync_sales_invoice: function(){
var me = this;
this.si_docs = this.get_submitted_invoice()
if(this.connection_status && this.si_docs.length){
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
args: {
doc_list: me.si_docs
},
callback: function(r){
if(r.message){
me.removed_items = r.message;
me.remove_doc_from_localstorage();
}
}
})
}
},
get_submitted_invoice: function(){
invoices = []
docs = this.get_doc_from_localstorage()
if(docs){
invoices = $.map(docs, function(data){
for(key in data){
if(data[key].docstatus == 1){
return data
}
}
});
}
return invoices
},
remove_doc_from_localstorage: function(){
var me = this;
this.si_docs = this.get_doc_from_localstorage();
if(this.removed_items){
$.each(this.si_docs, function(index, data){
for(key in data){
if(in_list(me.removed_items, key)){
me.si_docs.splice(index)
}
}
})
this.update_localstorage();
}
},
validate: function(){
var me = this;
this.customer_validate();
this.item_validate();
},
item_validate: function(){
if(this.frm.doc.items.length == 0){
frappe.throw(__("Select items to save the invoice"))
}
},
validate_serial_no: function(){
var me = this;
var item_code = serial_no = '';
for (key in this.item_serial_no){
item_code = key;
serial_no = me.item_serial_no[key]
}
if(item_code && serial_no){
$.each(this.frm.doc.items, function(index, data){
if(data.item_code == item_code){
if(in_list(data.serial_no.split('\n'), serial_no)){
frappe.throw(__(repl("Serial no %(serial_no)s is already taken", {
'serial_no': serial_no
})))
}
}
})
}
},
apply_pricing_rule: function(){
var me = this;
$.each(this.frm.doc["items"], function(n, item) {
pricing_rule = me.get_pricing_rule(item)
me.validate_pricing_rule(pricing_rule)
if(pricing_rule.length){
item.margin_type = pricing_rule[0].margin_type;
item.price_list_rate = pricing_rule[0].price || item.price_list_rate;
item.margin_rate_or_amount = pricing_rule[0].margin_rate_or_amount;
item.discount_percentage = pricing_rule[0].discount_percentage || 0.0;
me.apply_pricing_rule_on_item(item)
}
})
},
get_pricing_rule: function(item){
var me = this;
return $.grep(this.pricing_rules, function(data){
if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) {
if(in_list(['Customer', 'Customer Group', 'Territory'], data.applicable_for)){
return me.validate_condition(data)
}else{
return true
}
}
})
},
validate_condition: function(data){
//This method check condition based on applicable for
condition = this.get_mapper_for_pricing_rule(data)[data.applicable_for]
if(in_list(condition[1], condition[0])){
return true
}
},
get_mapper_for_pricing_rule: function(data){
return {
'Customer': [data.customer, [this.doc.customer]],
'Customer Group': [data.customer_group, [this.doc.customer_group, 'All Customer Groups']],
'Territory': [data.territory, [this.doc.territory, 'All Territories']],
}
},
validate_pricing_rule: function(pricing_rule){
//This method validate duplicate pricing rule
var pricing_rule_name = '';
var priority = 0;
var pricing_rule_list = [];
var priority_list = []
if(pricing_rule.length > 1){
$.each(pricing_rule, function(index, data){
pricing_rule_name += data.name + ','
priority_list.push(data.priority)
if(priority <= data.priority){
priority = data.priority
pricing_rule_list.push(data)
}
})
count = 0
$.each(priority_list, function(index, value){
if(value == priority){
count++
}
})
if(priority == 0 || count > 1){
frappe.throw(__(repl("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: %(pricing_rule)s", {
'pricing_rule': pricing_rule_name
})))
}
return pricing_rule_list
}
},
validate_warehouse: function(){
if(!this.items[0].default_warehouse){
frappe.throw(__("Deafault warehouse is required for selected item"))
}
}
})

View File

@ -37,6 +37,7 @@ def notify_status(doc, method):
party = frappe.get_doc(party_type, name) party = frappe.get_doc(party_type, name)
filters = get_filters_for(doc.doctype) filters = get_filters_for(doc.doctype)
party.flags.ignore_mandatory = True
status = None status = None
if filters: if filters:

View File

@ -33,6 +33,7 @@ class AccountsController(TransactionBase):
if self.meta.get_field("currency"): if self.meta.get_field("currency"):
self.calculate_taxes_and_totals() self.calculate_taxes_and_totals()
if not self.meta.get_field("is_return") or not self.is_return: if not self.meta.get_field("is_return") or not self.is_return:
self.validate_value("base_grand_total", ">=", 0) self.validate_value("base_grand_total", ">=", 0)
@ -55,16 +56,18 @@ class AccountsController(TransactionBase):
validate_recurring_document(self) validate_recurring_document(self)
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date")) convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
if self.doctype == 'Purchase Invoice':
self.validate_paid_amount() self.validate_paid_amount()
def validate_paid_amount(self): def validate_paid_amount(self):
if hasattr(self, "is_pos") or hasattr(self, "is_paid"): if hasattr(self, "is_pos") or hasattr(self, "is_paid"):
is_paid = self.get("is_pos") or self.get("is_paid") is_paid = self.get("is_pos") or self.get("is_paid")
if cint(is_paid) == 1: if cint(is_paid) == 1:
if flt(self.paid_amount) == 0: if flt(self.paid_amount) == 0 and flt(self.outstanding_amount) > 0:
if self.cash_bank_account: if self.cash_bank_account:
self.paid_amount = flt(flt(self.grand_total) - flt(self.write_off_amount), self.paid_amount = flt(flt(self.grand_total) - flt(self.write_off_amount),
self.precision("paid_amount")) self.precision("paid_amount"))
self.base_paid_amount = flt(self.paid_amount * self.conversion_rate, self.precision("base_paid_amount"))
else: else:
# show message that the amount is not paid # show message that the amount is not paid
self.paid_amount = 0 self.paid_amount = 0
@ -72,9 +75,6 @@ class AccountsController(TransactionBase):
else: else:
frappe.db.set(self,'paid_amount',0) frappe.db.set(self,'paid_amount',0)
frappe.db.set(self, 'base_paid_amount',
flt(self.paid_amount*self.conversion_rate, self.precision("base_paid_amount")))
def on_update_after_submit(self): def on_update_after_submit(self):
if self.meta.get_field("is_recurring"): if self.meta.get_field("is_recurring"):
validate_recurring_document(self) validate_recurring_document(self)

View File

@ -435,14 +435,40 @@ class calculate_taxes_and_totals(object):
- flt(self.doc.base_write_off_amount), self.doc.precision("grand_total")) - flt(self.doc.base_write_off_amount), self.doc.precision("grand_total"))
if self.doc.doctype == "Sales Invoice": if self.doc.doctype == "Sales Invoice":
self.calculate_paid_amount()
self.doc.round_floats_in(self.doc, ["paid_amount"]) self.doc.round_floats_in(self.doc, ["paid_amount"])
paid_amount = self.doc.paid_amount \ paid_amount = self.doc.paid_amount \
if self.doc.party_account_currency == self.doc.currency else self.doc.base_paid_amount if self.doc.party_account_currency == self.doc.currency else self.doc.base_paid_amount
self.doc.outstanding_amount = 0
if total_amount_to_pay > paid_amount:
self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount), self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount),
self.doc.precision("outstanding_amount")) self.doc.precision("outstanding_amount"))
self.change_amount()
elif self.doc.doctype == "Purchase Invoice": elif self.doc.doctype == "Purchase Invoice":
self.doc.outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount")) self.doc.outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount"))
def calculate_paid_amount(self):
paid_amount = base_paid_amount = 0.0
for payment in self.doc.get('payments'):
payment.base_amount = flt(payment.amount * self.doc.conversion_rate)
paid_amount += payment.amount
base_paid_amount += payment.base_amount
self.doc.paid_amount = flt(paid_amount, self.doc.precision("paid_amount"))
self.doc.base_paid_amount = flt(base_paid_amount, self.doc.precision("base_paid_amount"))
def change_amount(self):
change_amount = 0.0
if self.doc.paid_amount > self.doc.grand_total:
change_amount = flt(self.doc.paid_amount - self.doc.grand_total,
self.doc.precision("change_amount"))
self.doc.change_amount = change_amount;
self.doc.base_change_amount = flt(change_amount * self.doc.conversion_rate,
self.doc.precision("base_change_amount"))
def calculate_margin(self, item): def calculate_margin(self, item):
total_margin = 0.0 total_margin = 0.0
if item.price_list_rate: if item.price_list_rate:

View File

@ -16,13 +16,18 @@
"public/js/templates/address_list.html", "public/js/templates/address_list.html",
"public/js/templates/contact_list.html", "public/js/templates/contact_list.html",
"public/js/controllers/stock_controller.js", "public/js/controllers/stock_controller.js",
"public/js/controllers/payments.js",
"public/js/controllers/taxes_and_totals.js", "public/js/controllers/taxes_and_totals.js",
"public/js/controllers/transaction.js", "public/js/controllers/transaction.js",
"public/js/pos/pos.html", "public/js/pos/pos.html",
"public/js/pos/pos_bill_item.html", "public/js/pos/pos_bill_item.html",
"public/js/pos/pos_item.html", "public/js/pos/pos_item.html",
"public/js/pos/pos_tax_row.html", "public/js/pos/pos_tax_row.html",
"public/js/pos/pos_print.html",
"public/js/pos/pos.js", "public/js/pos/pos.js",
"public/js/pos/pos_invoice_list.html",
"public/js/payment/pos_payment.html",
"public/js/payment/payment_details.html",
"public/js/templates/item_selector.html", "public/js/templates/item_selector.html",
"public/js/utils/item_selector.js" "public/js/utils/item_selector.js"
], ],

View File

@ -124,3 +124,49 @@
.dashboard-list-item:last-child { .dashboard-list-item:last-child {
border-bottom: none; border-bottom: none;
} }
.payment-toolbar {
margin-left: 35px;
}
.payment-mode {
cursor: pointer;
font-family: sans-serif;
font-size: 15px;
}
.pos-payment-row .col-xs-6 {
padding :10px;
}
.pos-payment-row {
border-bottom:1px solid #d1d8dd;
margin: 2px 0px 5px 0px;
}
.pos-payment-row:hover {
background-color: #FCFFDD;
cursor: pointer;
}
.pos-keyboard-key, .delete-btn {
border: 1px solid #d1d8dd;
height:85px;
width:85px;
margin:10px 10px;
font-size:24px;
font-weight:200;
}
.amount-label {
font-size: 16px;
}
.selected-payment-mode {
background-color: #FCFFDD;
cursor: pointer;
}
.pos-invoice-list {
padding: 15px 10px;
}

View File

@ -0,0 +1,158 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
erpnext.payments = erpnext.stock.StockController.extend({
make_payment: function() {
var me = this;
this.dialog = new frappe.ui.Dialog({
title: 'Payment'
});
this.dialog.show();
this.$body = this.dialog.body;
this.dialog.$wrapper.find('.modal-dialog').css("width", "750px");
this.set_payment_primary_action();
this.make_keyboard();
},
set_payment_primary_action: function(){
var me = this;
this.dialog.set_primary_action(__("Submit"), function() {
frappe.confirm(__("Do you really want to submit the invoice?"), function () {
me.write_off_amount();
me.dialog.hide();
})
})
},
make_keyboard: function(){
var me = this;
$(this.$body).empty();
$(this.$body).html(frappe.render_template('pos_payment', this.frm.doc))
this.show_payment_details();
this.bind_keyboard_event()
},
pay_amount: function(){
var me = this;
this.make_multimode_payment();
this.calculate_outstanding_amount()
this.show_payment_details();
},
make_multimode_payment: function(){
var me = this;
if(this.frm.doc.change_amount > 0){
me.payment_val = me.doc.outstanding_amount
}
this.payments = frappe.model.add_child(this.frm.doc, 'Multi Mode Payment', "payments");
this.payments.mode_of_payment = this.dialog.fields_dict.mode_of_payment.get_value();
this.payments.amount = flt(this.payment_val);
},
show_payment_details: function(){
var me = this;
multimode_payments = $(this.$body).find('.multimode-payments').empty();
if(this.frm.doc.payments.length){
$.each(this.frm.doc.payments, function(index, data){
$(frappe.render_template('payment_details', {
mode_of_payment: data.mode_of_payment,
amount: data.amount,
idx: data.idx,
currency: me.frm.doc.currency,
type: data.type
})).appendTo(multimode_payments)
})
}else{
$("<p>No payment mode selected in pos profile</p>").appendTo(multimode_payments)
}
},
bind_keyboard_event: function(){
var me = this;
this.payment_val = '';
this.bind_payment_mode_keys_event();
this.bind_keyboard_keys_event();
},
bind_payment_mode_keys_event: function(){
var me = this;
$(this.$body).find('.pos-payment-row').click(function(){
me.idx = $(this).attr("idx");
me.selected_mode = $(me.$body).find(repl("input[idx='%(idx)s']",{'idx': me.idx}));
me.highlight_selected_row()
me.payment_val = 0.0
if(me.frm.doc.outstanding_amount > 0 && flt(me.selected_mode.val()) == 0.0){
//When user first time click on row
me.payment_val = flt(me.frm.doc.outstanding_amount)
me.selected_mode.val(format_number(me.payment_val, 2));
me.update_paid_amount()
me.bind_amount_change_event();
}else if(flt(me.selected_mode.val()) > 0){
//If user click on existing row which has value
me.payment_val = flt(me.selected_mode.val());
}
me.selected_mode.select()
})
},
highlight_selected_row: function(){
var me = this;
selected_row = $(this.$body).find(repl(".pos-payment-row[idx='%(idx)s']",{'idx': this.idx}));
$(this.$body).find('.pos-payment-row').removeClass('selected-payment-mode')
selected_row.addClass('selected-payment-mode')
$(this.$body).find('.amount').attr('disabled', true);
this.selected_mode.attr('disabled', false);
},
bind_keyboard_keys_event: function(){
var me = this;
$(this.$body).find('.pos-keyboard-key').click(function(){
me.payment_val += $(this).text();
me.selected_mode.val(format_number(me.payment_val, 2))
me.idx = me.selected_mode.attr("idx")
me.update_paid_amount()
})
$(this.$body).find('.delete-btn').click(function(){
me.payment_val = cstr(flt(me.selected_mode.val())).slice(0, -1);
me.selected_mode.val(format_number(me.payment_val, 2));
me.idx = me.selected_mode.attr("idx")
me.update_paid_amount();
})
},
bind_amount_change_event: function(){
var me = this;
me.selected_mode.change(function(){
me.payment_val = $(this).val() || 0.0;
me.selected_mode.val(format_number(me.payment_val, 2))
me.idx = me.selected_mode.attr("idx")
me.update_paid_amount()
})
},
update_paid_amount: function(){
var me = this;
$.each(this.frm.doc.payments, function(index, data){
if(cint(me.idx) == cint(data.idx)){
data.amount = flt(me.selected_mode.val(), 2)
}
})
this.calculate_outstanding_amount();
this.show_amounts();
},
show_amounts: function(){
var me = this;
$(this.$body).find('.paid_amount').text(format_currency(this.frm.doc.paid_amount, this.frm.doc.currency));
$(this.$body).find('.change_amount').text(format_currency(this.frm.doc.change_amount, this.frm.doc.currency))
$(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, this.frm.doc.currency))
this.update_invoice();
}
})

View File

@ -1,13 +1,30 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
erpnext.taxes_and_totals = erpnext.stock.StockController.extend({ erpnext.taxes_and_totals = erpnext.payments.extend({
apply_pricing_rule_on_item: function(item){
if(!item.margin_type){
item.margin_rate_or_amount = 0.0;
}
if(item.margin_type == "Percentage"){
item.total_margin = item.price_list_rate + item.price_list_rate * ( item.margin_rate_or_amount / 100);
}else{
item.total_margin = item.price_list_rate + item.margin_rate_or_amount;
}
item.rate = flt(item.total_margin , 2);
if(item.discount_percentage){
discount_value = flt(item.total_margin) * flt(item.discount_percentage) / 100;
item.rate = flt((item.total_margin) - (discount_value), precision('rate'));
}
},
calculate_taxes_and_totals: function(update_paid_amount) { calculate_taxes_and_totals: function(update_paid_amount) {
this.discount_amount_applied = false; this.discount_amount_applied = false;
this._calculate_taxes_and_totals(); this._calculate_taxes_and_totals();
this.calculate_discount_amount();
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount"))
this.apply_discount_amount();
// Advance calculation applicable to Sales /Purchase Invoice // Advance calculation applicable to Sales /Purchase Invoice
if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype) if(in_list(["Sales Invoice", "Purchase Invoice"], this.frm.doc.doctype)
@ -24,6 +41,11 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.frm.refresh_fields(); this.frm.refresh_fields();
}, },
calculate_discount_amount: function(){
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount"))
this.apply_discount_amount();
},
_calculate_taxes_and_totals: function() { _calculate_taxes_and_totals: function() {
this.validate_conversion_rate(); this.validate_conversion_rate();
this.calculate_item_values(); this.calculate_item_values();
@ -98,7 +120,7 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
$.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0 }); $.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0 });
if (!this.discount_amount_applied) { if (!this.discount_amount_applied && cur_frm) {
cur_frm.cscript.validate_taxes_and_charges(tax.doctype, tax.name); cur_frm.cscript.validate_taxes_and_charges(tax.doctype, tax.name);
me.validate_inclusive_tax(tax); me.validate_inclusive_tax(tax);
} }
@ -433,13 +455,14 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
apply_discount_amount: function() { apply_discount_amount: function() {
var me = this; var me = this;
var distributed_amount = 0.0; var distributed_amount = 0.0;
this.frm.doc.base_discount_amount = 0.0;
if (this.frm.doc.discount_amount) { if (this.frm.doc.discount_amount) {
if(!this.frm.doc.apply_discount_on) if(!this.frm.doc.apply_discount_on)
frappe.throw(__("Please select Apply Discount On")); frappe.throw(__("Please select Apply Discount On"));
this.frm.set_value("base_discount_amount", this.frm.doc.base_discount_amount = flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate,
flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate, precision("base_discount_amount"))) precision("base_discount_amount"));
var total_for_discount_amount = this.get_total_for_discount_amount(); var total_for_discount_amount = this.get_total_for_discount_amount();
// calculate item amount after Discount Amount // calculate item amount after Discount Amount
@ -455,8 +478,6 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.discount_amount_applied = true; this.discount_amount_applied = true;
this._calculate_taxes_and_totals(); this._calculate_taxes_and_totals();
} }
} else {
this.frm.set_value("base_discount_amount", 0);
} }
}, },
@ -524,18 +545,59 @@ erpnext.taxes_and_totals = erpnext.stock.StockController.extend({
this.frm.doc.paid_amount = 0 this.frm.doc.paid_amount = 0
} }
this.set_in_company_currency(this.frm.doc, ["paid_amount"]); this.set_in_company_currency(this.frm.doc, ["paid_amount"]);
if(this.frm.refresh_field){
this.frm.refresh_field("paid_amount"); this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount"); this.frm.refresh_field("base_paid_amount");
}
if(this.frm.doc.doctype == "Sales Invoice"){
this.calculate_paid_amount()
}
var outstanding_amount = 0.0
var paid_amount = (this.frm.doc.party_account_currency == this.frm.doc.currency) ? var paid_amount = (this.frm.doc.party_account_currency == this.frm.doc.currency) ?
this.frm.doc.paid_amount : this.frm.doc.base_paid_amount; this.frm.doc.paid_amount : this.frm.doc.base_paid_amount;
var outstanding_amount = flt(total_amount_to_pay - flt(paid_amount), if (total_amount_to_pay > paid_amount){
outstanding_amount = flt(total_amount_to_pay - flt(paid_amount),
precision("outstanding_amount")); precision("outstanding_amount"));
}
} else if(this.frm.doc.doctype == "Purchase Invoice") { } else if(this.frm.doc.doctype == "Purchase Invoice") {
var outstanding_amount = flt(total_amount_to_pay, precision("outstanding_amount")); var outstanding_amount = flt(total_amount_to_pay, precision("outstanding_amount"));
} }
this.frm.set_value("outstanding_amount", outstanding_amount);
this.frm.doc.outstanding_amount = outstanding_amount;
this.calculate_change_amount()
},
calculate_paid_amount: function(){
var me = this;
var paid_amount = base_paid_amount = 0.0;
$.each(this.frm.doc['payments'] || [], function(index, data){
if(data.amount > 0){
data.base_amount = flt(data.amount * me.frm.doc.conversion_rate);
paid_amount += data.amount;
base_paid_amount += data.base_amount;
} }
}) })
this.frm.doc.paid_amount = flt(paid_amount, precision("paid_amount"));
this.frm.doc.base_paid_amount = flt(base_paid_amount, precision("base_paid_amount"));
},
calculate_change_amount: function(){
var change_amount = 0.0;
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
change_amount = flt(this.frm.doc.paid_amount - this.frm.doc.grand_total,
precision("change_amount"))
}
this.frm.doc.change_amount = flt(change_amount,
precision("change_amount"))
this.frm.doc.base_change_amount = flt(change_amount * this.frm.doc.conversion_rate,
precision("base_change_amount"))
},
})

View File

@ -165,7 +165,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
erpnext.hide_company(); erpnext.hide_company();
this.show_item_wise_taxes(); this.show_item_wise_taxes();
this.set_dynamic_labels(); this.set_dynamic_labels();
erpnext.pos.make_pos_btn(this.frm); // erpnext.pos.make_pos_btn(this.frm);
this.setup_sms(); this.setup_sms();
this.make_show_payments_btn(); this.make_show_payments_btn();
}, },
@ -550,7 +550,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
setup_field_label_map(["base_total", "base_net_total", "base_total_taxes_and_charges", setup_field_label_map(["base_total", "base_net_total", "base_total_taxes_and_charges",
"base_discount_amount", "base_grand_total", "base_rounded_total", "base_in_words", "base_discount_amount", "base_grand_total", "base_rounded_total", "base_in_words",
"base_taxes_and_charges_added", "base_taxes_and_charges_deducted", "total_amount_to_pay", "base_taxes_and_charges_added", "base_taxes_and_charges_deducted", "total_amount_to_pay",
"base_paid_amount", "base_write_off_amount" "base_paid_amount", "base_write_off_amount", "base_change_amount"
], company_currency); ], company_currency);
setup_field_label_map(["total", "net_total", "total_taxes_and_charges", "discount_amount", setup_field_label_map(["total", "net_total", "total_taxes_and_charges", "discount_amount",

View File

@ -0,0 +1,4 @@
<div class="row pos-payment-row" type="{{type}}" idx={{idx}}>
<div class="col-xs-6"><h5 class="payment-mode text-ellipsis" idx="{{idx}}"> {{mode_of_payment}} </h5></div>
<div class="col-xs-6 text-right"><input disabled data-fieldtype="Currency" class="input-with-feedback form-control text-right amount" idx="{{idx}}" type="text" value="{{format_number(amount, 2)}}"></div>
</div>

View File

@ -0,0 +1,40 @@
<div class="pos_payment row">
<div class="col-sm-6">
<div class="row">
<div class="col-xs-6 text-center">
<p class="amount-label"> Total <h3>{%= format_currency(grand_total, currency) %} </h3></p>
</div>
<div class="col-xs-6 text-center">
<p class="amount-label"> Paid <h3 class="paid_amount">{%= format_currency(paid_amount, currency) %}</h3></p>
</div>
</div>
<hr>
<div class="multimode-payments">
</div>
</div>
<div class="col-sm-6">
<div class="row">
<div class="col-xs-6 text-center">
<p class="amount-label"> Outstanding <h3 class="outstanding_amount">{%= format_currency(outstanding_amount, currency) %} </h3></p>
</div>
<div class="col-xs-6 text-center">
<p class="amount-label"> Change <h3 class="change_amount">{%= format_currency(change_amount, currency) %}</h3></p>
</div>
</div>
<hr>
<div class="payment-toolbar">
{% for(var i=0; i<3; i++) { %}
<div class="row">
{% for(var j=i*3; j<(i+1)*3; j++) { %}
<button type="button" class="btn btn-default pos-keyboard-key">{{j+1}}</button>
{% } %}
</div>
{% } %}
<div class="row">
<button type="button" class="btn btn-default delete-btn"><span class="mega-octicon octicon-triangle-left"></span></button>
<button type="button" class="btn btn-default pos-keyboard-key">0</button>
<button type="button" class="btn btn-default pos-keyboard-key">.</button>
</div>
</div>
</div>
</div>

View File

@ -24,6 +24,7 @@
<div class="tax-table small"></div> <div class="tax-table small"></div>
</div> </div>
</div> </div>
{% if (apply_discount_on) { %}
<div class="row pos-bill-row discount-amount-area"> <div class="row pos-bill-row discount-amount-area">
<div class="col-xs-6"><h6 class="text-muted">{%= __("Discount") %}</h6></div> <div class="col-xs-6"><h6 class="text-muted">{%= __("Discount") %}</h6></div>
<div class="col-xs-3 discount-field-col"> <div class="col-xs-3 discount-field-col">
@ -40,6 +41,7 @@
</div> </div>
</div> </div>
</div> </div>
{% } %}
<div class="row pos-bill-row grand-total-area"> <div class="row pos-bill-row grand-total-area">
<div class="col-xs-6"><h6>{%= __("Grand Total") %}</h6></div> <div class="col-xs-6"><h6>{%= __("Grand Total") %}</h6></div>
<div class="col-xs-6"><h6 class="grand-total text-right"></h6></div> <div class="col-xs-6"><h6 class="grand-total text-right"></h6></div>
@ -51,11 +53,12 @@
<div class="row pos-item-area"> <div class="row pos-item-area">
</div> </div>
<span id="customer-results" style="color:#68a;"></span>
<div class="row pos-item-toolbar"> <div class="row pos-item-toolbar">
<div class="search-area col-xs-12"></div> <div class="search-area col-xs-12"></div>
</div> </div>
<div class="item-list-area"> <div class="item-list-area">
<div class="item-list"></div> <div class="app-listing item-list"></ul>
</div> </div>
</div> </div>
</div> </div>

View File

@ -10,7 +10,6 @@
{% if(actual_qty != null) { %} {% if(actual_qty != null) { %}
<div style="margin-top: 5px;" class="text-muted small text-right"> <div style="margin-top: 5px;" class="text-muted small text-right">
<span title="{%= __("In Stock") %}">{%= actual_qty || 0 %}<span> <span title="{%= __("In Stock") %}">{%= actual_qty || 0 %}<span>
<span title="{%= __("Projected") %}">({%= projected_qty || 0 %})<span>
</div> </div>
{% } %} {% } %}
</div> </div>

View File

@ -0,0 +1,5 @@
<div class="row list-row pos-invoice-list" invoice-name = "{{name}}">
<div class="col-xs-6">{%= customer %}</div>
<div class="col-xs-3 text-right">{%= grand_total %}</div>
<div class="col-xs-3 text-right">{%= status %}</div>
</div>

View File

@ -0,0 +1,25 @@
<style>
.print-format table, .print-format tr,
.print-format td, .print-format div, .print-format p {
font-family: Monospace;
line-height: 200%;
vertical-align: middle;
}
@media screen {
.print-format {
width: 4in;
padding: 0.25in;
min-height: 8in;
}
}
</style>
<p class="text-center">
{{ company }}<br>
</p>
<p>
{{currency}}
</p>
{% for item in items %}
<p> {{item.item_code}} </p>
{% endfor %}

View File

@ -122,7 +122,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
// check if child doctype is Sales Order Item/Qutation Item and calculate the rate // check if child doctype is Sales Order Item/Qutation Item and calculate the rate
if(in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item"]), cdt) if(in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item"]), cdt)
this.calculate_revised_margin_and_rate(item, doc,cdt, cdn); this.apply_pricing_rule_on_item(item);
else else
item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0), item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0),
precision("rate", item)); precision("rate", item));
@ -320,7 +320,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
margin_rate_or_amount: function(doc, cdt, cdn) { margin_rate_or_amount: function(doc, cdt, cdn) {
// calculated the revised total margin and rate on margin rate changes // calculated the revised total margin and rate on margin rate changes
item = locals[cdt][cdn]; item = locals[cdt][cdn];
this.calculate_revised_margin_and_rate(item) this.apply_pricing_rule_on_item(item)
this.calculate_taxes_and_totals(); this.calculate_taxes_and_totals();
cur_frm.refresh_fields(); cur_frm.refresh_fields();
}, },
@ -328,26 +328,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
margin_type: function(doc, cdt, cdn){ margin_type: function(doc, cdt, cdn){
// calculate the revised total margin and rate on margin type changes // calculate the revised total margin and rate on margin type changes
item = locals[cdt][cdn]; item = locals[cdt][cdn];
this.calculate_revised_margin_and_rate(item, doc,cdt, cdn) this.apply_pricing_rule_on_item(item, doc,cdt, cdn)
this.calculate_taxes_and_totals(); this.calculate_taxes_and_totals();
cur_frm.refresh_fields(); cur_frm.refresh_fields();
},
calculate_revised_margin_and_rate: function(item){
if(in_list(["Percentage", "Amount"], item.margin_type)){
if(item.margin_type == "Percentage")
item.total_margin = item.price_list_rate + item.price_list_rate * ( item.margin_rate_or_amount / 100);
else
item.total_margin = item.price_list_rate + item.margin_rate_or_amount;
item.rate = flt(item.total_margin * (1 - item.discount_percentage / 100.0),
precision("rate", item));
}
else{
item.rate_or_amount = 0.0;
item.total_margin = 0.0;
item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0),
precision("rate", item));
}
} }
}); });