예제 #1
0
 def check_prev_docstatus(self):
     for d in getlist(self.doclist, 'entries'):
         if d.purchase_order:
             submitted = frappe.db.sql(
                 "select name from `tabPurchase Order` where docstatus = 1 and name = '%s'"
                 % d.purchase_order)
             if not submitted:
                 frappe.throw("Purchase Order : " + cstr(d.purchase_order) +
                              " is not submitted")
         if d.purchase_receipt:
             submitted = frappe.db.sql(
                 "select name from `tabPurchase Receipt` where docstatus = 1 and name = '%s'"
                 % d.purchase_receipt)
             if not submitted:
                 frappe.throw("Purchase Receipt : " +
                              cstr(d.purchase_receipt) +
                              " is not submitted")
예제 #2
0
    def update_bin(self, is_submit, is_stopped=0):
        from erpnext.stock.utils import update_bin
        pc_obj = get_obj('Purchase Common')
        for d in getlist(self.doclist, 'po_details'):
            #1. Check if is_stock_item == 'Yes'
            if frappe.db.get_value("Item", d.item_code,
                                   "is_stock_item") == "Yes":
                # this happens when item is changed from non-stock to stock item
                if not d.warehouse:
                    continue

                ind_qty, po_qty = 0, flt(d.qty) * flt(d.conversion_factor)
                if is_stopped:
                    po_qty = flt(d.qty) > flt(d.received_qty) and \
                     flt( flt(flt(d.qty) - flt(d.received_qty))*flt(d.conversion_factor)) or 0

                # No updates in Material Request on Stop / Unstop
                if cstr(d.prevdoc_doctype
                        ) == 'Material Request' and not is_stopped:
                    # get qty and pending_qty of prevdoc
                    curr_ref_qty = pc_obj.get_qty(
                        d.doctype, 'prevdoc_detail_docname',
                        d.prevdoc_detail_docname, 'Material Request Item',
                        'Material Request - Purchase Order', self.doc.name)
                    max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
                      flt(curr_ref_qty.split('~~~')[0]), 0

                    if flt(qty) + flt(po_qty) > flt(max_qty):
                        curr_qty = flt(max_qty) - flt(qty)
                        # special case as there is no restriction
                        # for Material Request - Purchase Order
                        curr_qty = curr_qty > 0 and curr_qty or 0
                    else:
                        curr_qty = flt(po_qty)

                    ind_qty = -flt(curr_qty)

                # Update ordered_qty and indented_qty in bin
                args = {
                    "item_code": d.item_code,
                    "warehouse": d.warehouse,
                    "ordered_qty": (is_submit and 1 or -1) * flt(po_qty),
                    "indented_qty": (is_submit and 1 or -1) * flt(ind_qty),
                    "posting_date": self.doc.transaction_date
                }
                update_bin(args)
예제 #3
0
    def validate_accepted_rejected_qty(self):
        for d in getlist(self.doclist, "purchase_receipt_details"):
            if not flt(d.received_qty) and flt(d.qty):
                d.received_qty = flt(d.qty) - flt(d.rejected_qty)

            elif not flt(d.qty) and flt(d.rejected_qty):
                d.qty = flt(d.received_qty) - flt(d.rejected_qty)

            elif not flt(d.rejected_qty):
                d.rejected_qty = flt(d.received_qty) - flt(d.qty)

            # Check Received Qty = Accepted Qty + Rejected Qty
            if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)):

                msgprint(
                    "Sum of Accepted Qty and Rejected Qty must be equal to Received quantity. Error for Item: "
                    + cstr(d.item_code))
                raise Exception
예제 #4
0
	def get_stock_and_rate(self):
		"""get stock and incoming rate on posting date"""
		for d in getlist(self.doclist, 'mtn_details'):
			args = frappe._dict({
				"item_code": d.item_code,
				"warehouse": d.s_warehouse or d.t_warehouse,
				"posting_date": self.doc.posting_date,
				"posting_time": self.doc.posting_time,
				"qty": d.s_warehouse and -1*d.transfer_qty or d.transfer_qty,
				"serial_no": d.serial_no,
				"bom_no": d.bom_no,
			})
			# get actual stock at source warehouse
			d.actual_qty = get_previous_sle(args).get("qty_after_transaction") or 0
			
			# get incoming rate
			if not flt(d.incoming_rate):
				d.incoming_rate = self.get_incoming_rate(args)
				
			d.amount = flt(d.transfer_qty) * flt(d.incoming_rate)
예제 #5
0
    def check_item_tax(self):
        """Check whether Tax Rate is not entered twice for same Tax Type"""
        check_list = []
        for d in getlist(self.doclist, 'item_tax'):
            if d.tax_type:
                account_type = frappe.db.get_value("Account", d.tax_type,
                                                   "account_type")

                if account_type not in [
                        'Tax', 'Chargeable', 'Income Account',
                        'Expense Account'
                ]:
                    msgprint(
                        "'%s' is not Tax / Chargeable / Income / Expense Account"
                        % d.tax_type,
                        raise_exception=1)
                else:
                    if d.tax_type in check_list:
                        msgprint("Rate is entered twice for: '%s'" %
                                 d.tax_type,
                                 raise_exception=1)
                    else:
                        check_list.append(d.tax_type)
예제 #6
0
    def validate_conversion_factor(self):
        check_list = []
        for d in getlist(self.doclist, 'uom_conversion_details'):
            if cstr(d.uom) in check_list:
                msgprint(_(
                    "UOM %s has been entered more than once in Conversion Factor Table."
                    % cstr(d.uom)),
                         raise_exception=1)
            else:
                check_list.append(cstr(d.uom))

            if d.uom and cstr(d.uom) == cstr(
                    self.doc.stock_uom) and flt(d.conversion_factor) != 1:
                msgprint(_(
                    """Conversion Factor of UOM: %s should be equal to 1. As UOM: %s is Stock UOM of Item: %s."""
                    % (d.uom, d.uom, self.doc.name)),
                         raise_exception=1)
            elif d.uom and cstr(d.uom) != self.doc.stock_uom and flt(
                    d.conversion_factor) == 1:
                msgprint(_(
                    """Conversion Factor of UOM: %s should not be equal to 1. As UOM: %s is not Stock UOM of Item: %s"""
                    % (d.uom, d.uom, self.doc.name)),
                         raise_exception=1)
    def reconcile(self):
        """
			Links booking and payment voucher
			1. cancel payment voucher
			2. split into multiple rows if partially adjusted, assign against voucher
			3. submit payment voucher
		"""
        if not self.doc.voucher_no or not frappe.db.sql(
                """select name from `tab%s` 
				where name = %s""" % (self.doc.voucher_type, '%s'), self.doc.voucher_no):
            msgprint("Please select valid Voucher No to proceed",
                     raise_exception=1)

        lst = []
        for d in getlist(self.doclist, 'ir_payment_details'):
            if flt(d.amt_to_be_reconciled) > 0:
                args = {
                    'voucher_no': d.voucher_no,
                    'voucher_detail_no': d.voucher_detail_no,
                    'against_voucher_type': self.doc.voucher_type,
                    'against_voucher': self.doc.voucher_no,
                    'account': self.doc.account,
                    'is_advance': 'No',
                    'dr_or_cr': self.doc.account_type == 'debit' and 'credit'
                    or 'debit',
                    'unadjusted_amt': flt(d.amt_due),
                    'allocated_amt': flt(d.amt_to_be_reconciled)
                }

                lst.append(args)

        if lst:
            from erpnext.accounts.utils import reconcile_against_document
            reconcile_against_document(lst)
            msgprint("Successfully allocated.")
        else:
            msgprint("No amount allocated.", raise_exception=1)
예제 #8
0
    def validate_materials(self):
        """ Validate raw material entries """
        check_list = []
        for m in getlist(self.doclist, 'bom_materials'):
            # check if operation no not in op table
            if self.doc.with_operations and cstr(
                    m.operation_no) not in self.op:
                msgprint("""Operation no: %s against item: %s at row no: %s \
					is not present at Operations table""" %
                         (m.operation_no, m.item_code, m.idx),
                         raise_exception=1)

            item = self.get_item_det(m.item_code)
            if item[0]['is_manufactured_item'] == 'Yes':
                if not m.bom_no:
                    msgprint(
                        "Please enter BOM No aginst item: %s at row no: %s" %
                        (m.item_code, m.idx),
                        raise_exception=1)
                else:
                    self.validate_bom_no(m.item_code, m.bom_no, m.idx)

            elif m.bom_no:
                msgprint(
                    """As Item %s is not a manufactured / sub-contracted item, \
					you can not enter BOM against it (Row No: %s).""" % (m.item_code, m.idx),
                    raise_exception=1)

            if flt(m.qty) <= 0:
                msgprint(
                    "Please enter qty against raw material: %s at row no: %s" %
                    (m.item_code, m.idx),
                    raise_exception=1)

            self.check_if_item_repeated(m.item_code, m.operation_no,
                                        check_list)
예제 #9
0
    def validate_approving_authority(self,
                                     doctype_name,
                                     company,
                                     total,
                                     doc_obj=''):
        av_dis = 0
        if doc_obj:
            price_list_rate, base_rate = 0, 0
            for d in getlist(doc_obj.doclist, doc_obj.fname):
                if d.base_price_list_rate and d.base_rate:
                    price_list_rate += flt(d.base_price_list_rate)
                    base_rate += flt(d.base_rate)
            if price_list_rate:
                av_dis = 100 - flt(base_rate * 100 / price_list_rate)

        final_based_on = [
            'Grand Total', 'Average Discount', 'Customerwise Discount',
            'Itemwise Discount'
        ]
        # Individual User
        # ================
        # Check for authorization set for individual user

        based_on = [
            x[0] for x in frappe.db.sql(
                "select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2",
                (doctype_name, session['user'], company))
        ]

        for d in based_on:
            self.bifurcate_based_on_type(doctype_name, total, av_dis, d,
                                         doc_obj, 1, company)

        # Remove user specific rules from global authorization rules
        for r in based_on:
            if r in final_based_on and r != 'Itemwise Discount':
                final_based_on.remove(r)

        # Specific Role
        # ===============
        # Check for authorization set on particular roles
        based_on = [
            x[0] for x in frappe.db.sql(
                """select based_on 
			from `tabAuthorization Rule` 
			where transaction = %s and system_role IN (%s) and based_on IN (%s) 
			and (company = %s or ifnull(company,'')='') 
			and docstatus != 2
		""" % ('%s', "'" + "','".join(frappe.user.get_roles()) + "'", "'" +
         "','".join(final_based_on) + "'", '%s'), (doctype_name, company))
        ]

        for d in based_on:
            self.bifurcate_based_on_type(doctype_name, total, av_dis, d,
                                         doc_obj, 2, company)

        # Remove role specific rules from global authorization rules
        for r in based_on:
            if r in final_based_on and r != 'Itemwise Discount':
                final_based_on.remove(r)

        # Global Rule
        # =============
        # Check for global authorization
        for g in final_based_on:
            self.bifurcate_based_on_type(doctype_name, total, av_dis, g,
                                         doc_obj, 0, company)
예제 #10
0
 def get_schedule_dates(self):
     for d in getlist(self.doclist, 'po_details'):
         if d.prevdoc_detail_docname and not d.schedule_date:
             d.schedule_date = frappe.db.get_value("Material Request Item",
                                                   d.prevdoc_detail_docname,
                                                   "schedule_date")
예제 #11
0
 def check_item_table(self):
     if not (getlist(self.doclist, 'installed_item_details')):
         msgprint("Please fetch items from Delivery Note selected",
                  raise_exception=1)
예제 #12
0
 def fill_customer_code(self):
     """ Append all the customer codes and insert into "customer_code" field of item table """
     cust_code = []
     for d in getlist(self.doclist, 'item_customer_details'):
         cust_code.append(d.ref_code)
     self.doc.customer_code = ','.join(cust_code)
예제 #13
0
	def validate_finished_goods(self):
		"""validation: finished good quantity should be same as manufacturing quantity"""
		for d in getlist(self.doclist, 'mtn_details'):
			if d.bom_no and flt(d.transfer_qty) != flt(self.doc.fg_completed_qty):
				msgprint(_("Row #") + " %s: " % d.idx 
					+ _("Quantity should be equal to Manufacturing Quantity. To fetch items again, click on 'Get Items' button or update the Quantity manually."), raise_exception=1)