コード例 #1
0
    def test_gratuity_based_on_all_previous_slabs_via_payment_entry(self):
        """
		Range	|	Fraction
		0-1		|	0
		1-5		|	0.7
		5-0		|	1
		"""
        from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry

        doj = add_days(getdate(), -(6 * 365))
        relieving_date = getdate()

        employee = make_employee(
            "*****@*****.**",
            company="_Test Company",
            date_of_joining=doj,
            relieving_date=relieving_date,
        )

        sal_slip = create_salary_slip("*****@*****.**")
        rule = get_gratuity_rule("Rule Under Limited Contract (UAE)")
        set_mode_of_payment_account()

        gratuity = create_gratuity(expense_account="Payment Account - _TC",
                                   mode_of_payment="Cash",
                                   employee=employee)

        # work experience calculation
        employee_total_workings_days = (get_datetime(relieving_date) -
                                        get_datetime(doj)).days
        experience = floor(employee_total_workings_days /
                           rule.total_working_days_per_year)
        self.assertEqual(gratuity.current_work_experience, experience)

        # amount calculation
        component_amount = frappe.get_all(
            "Salary Detail",
            filters={
                "docstatus": 1,
                "parent": sal_slip,
                "parentfield": "earnings",
                "salary_component": "Basic Salary",
            },
            fields=["amount"],
            limit=1,
        )

        gratuity_amount = ((0 * 1) + (4 * 0.7) +
                           (1 * 1)) * component_amount[0].amount
        self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))
        self.assertEqual(gratuity.status, "Unpaid")

        pe = get_payment_entry("Gratuity", gratuity.name)
        pe.reference_no = "123467"
        pe.reference_date = getdate()
        pe.submit()

        gratuity.reload()
        self.assertEqual(gratuity.status, "Paid")
        self.assertEqual(flt(gratuity.paid_amount, 2), flt(gratuity.amount, 2))
コード例 #2
0
    def test_gratuity_based_on_current_slab_via_additional_salary(self):
        """
		Range	|	Fraction
		5-0		|	1
		"""
        doj = add_days(getdate(), -(6 * 365))
        relieving_date = getdate()

        employee = make_employee(
            "*****@*****.**",
            company="_Test Company",
            date_of_joining=doj,
            relieving_date=relieving_date,
        )
        sal_slip = create_salary_slip("*****@*****.**")

        rule = get_gratuity_rule(
            "Rule Under Unlimited Contract on termination (UAE)")

        gratuity = create_gratuity(pay_via_salary_slip=1,
                                   employee=employee,
                                   rule=rule.name)

        # work experience calculation
        employee_total_workings_days = (get_datetime(relieving_date) -
                                        get_datetime(doj)).days
        experience = floor(employee_total_workings_days /
                           rule.total_working_days_per_year)
        self.assertEqual(gratuity.current_work_experience, experience)

        # amount calculation
        component_amount = frappe.get_all(
            "Salary Detail",
            filters={
                "docstatus": 1,
                "parent": sal_slip,
                "parentfield": "earnings",
                "salary_component": "Basic Salary",
            },
            fields=["amount"],
            limit=1,
        )
        gratuity_amount = component_amount[0].amount * experience
        self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))

        # additional salary creation (Pay via salary slip)
        self.assertTrue(
            frappe.db.exists("Additional Salary",
                             {"ref_docname": gratuity.name}))

        # gratuity should be marked "Paid" on the next salary slip submission
        salary_slip = make_salary_slip("Test Gratuity", employee=employee)
        salary_slip.posting_date = getdate()
        salary_slip.insert()
        salary_slip.submit()

        gratuity.reload()
        self.assertEqual(gratuity.status, "Paid")
コード例 #3
0
def get_items_with_location_and_quantity(item_doc, item_location_map):
    available_locations = item_location_map.get(item_doc.item_code)
    locations = []

    remaining_stock_qty = item_doc.stock_qty
    while remaining_stock_qty > 0 and available_locations:
        item_location = available_locations.pop(0)
        item_location = frappe._dict(item_location)

        stock_qty = remaining_stock_qty if item_location.qty >= remaining_stock_qty else item_location.qty
        qty = stock_qty / (item_doc.conversion_factor or 1)

        uom_must_be_whole_number = frappe.db.get_value('UOM', item_doc.uom,
                                                       'must_be_whole_number')
        if uom_must_be_whole_number:
            qty = floor(qty)
            stock_qty = qty * item_doc.conversion_factor
            if not stock_qty: break

        serial_nos = None
        if item_location.serial_no:
            serial_nos = '\n'.join(item_location.serial_no[0:cint(stock_qty)])

        auto_set_serial_no = frappe.db.get_single_value(
            "Stock Settings", "automatically_set_serial_nos_based_on_fifo")
        auto_set_batch_no = frappe.db.get_single_value(
            "Stock Settings", "automatically_set_batch_nos_based_on_fifo")

        locations.append(
            frappe._dict({
                'qty':
                qty,
                'stock_qty':
                stock_qty,
                'warehouse':
                item_location.warehouse,
                'serial_no':
                serial_nos if auto_set_serial_no else item_doc.serial_no,
                'batch_no':
                item_location.batch_no
                if auto_set_batch_no else item_doc.batch_no
            }))

        remaining_stock_qty -= stock_qty

        qty_diff = item_location.qty - stock_qty
        # if extra quantity is available push current warehouse to available locations
        if qty_diff > 0:
            item_location.qty = qty_diff
            if item_location.serial_no:
                # set remaining serial numbers
                item_location.serial_no = item_location.serial_no[-qty_diff:]
            available_locations = [item_location] + available_locations

    # update available locations for the item
    item_location_map[item_doc.item_code] = available_locations
    return locations
コード例 #4
0
def get_items_with_location_and_quantity(item_doc, item_location_map,
                                         docstatus):
    available_locations = item_location_map.get(item_doc.item_code)
    locations = []

    # if stock qty is zero on submitted entry, show positive remaining qty to recalculate in case of restock.
    remaining_stock_qty = (item_doc.qty if
                           (docstatus == 1 and item_doc.stock_qty == 0) else
                           item_doc.stock_qty)

    while remaining_stock_qty > 0 and available_locations:
        item_location = available_locations.pop(0)
        item_location = frappe._dict(item_location)

        stock_qty = (remaining_stock_qty
                     if item_location.qty >= remaining_stock_qty else
                     item_location.qty)
        qty = stock_qty / (item_doc.conversion_factor or 1)

        uom_must_be_whole_number = frappe.db.get_value("UOM", item_doc.uom,
                                                       "must_be_whole_number")
        if uom_must_be_whole_number:
            qty = floor(qty)
            stock_qty = qty * item_doc.conversion_factor
            if not stock_qty:
                break

        serial_nos = None
        if item_location.serial_no:
            serial_nos = "\n".join(item_location.serial_no[0:cint(stock_qty)])

        locations.append(
            frappe._dict({
                "qty": qty,
                "stock_qty": stock_qty,
                "warehouse": item_location.warehouse,
                "serial_no": serial_nos,
                "batch_no": item_location.batch_no,
            }))

        remaining_stock_qty -= stock_qty

        qty_diff = item_location.qty - stock_qty
        # if extra quantity is available push current warehouse to available locations
        if qty_diff > 0:
            item_location.qty = qty_diff
            if item_location.serial_no:
                # set remaining serial numbers
                item_location.serial_no = item_location.serial_no[-int(qty_diff
                                                                       ):]
            available_locations = [item_location] + available_locations

    # update available locations for the item
    item_location_map[item_doc.item_code] = available_locations
    return locations
コード例 #5
0
ファイル: filters.py プロジェクト: ankush/erpnext
	def get_discount_filters(self, discounts):
		discount_filters = []

		# [25.89, 60.5] min max
		min_discount, max_discount = discounts[0], discounts[1]
		# [25, 60] rounded min max
		min_range_absolute, max_range_absolute = floor(min_discount), floor(max_discount)

		min_range = int(min_discount - (min_range_absolute % 10))  # 20
		max_range = int(max_discount - (max_range_absolute % 10))  # 60

		min_range = (
			(min_range + 10) if min_range != min_range_absolute else min_range
		)  # 30 (upper limit of 25.89 in range of 10)
		max_range = (max_range + 10) if max_range != max_range_absolute else max_range  # 60

		for discount in range(min_range, (max_range + 1), 10):
			label = f"{discount}% and below"
			discount_filters.append([discount, label])

		return discount_filters
コード例 #6
0
 def test_floor(self):
     from decimal import Decimal
     self.assertEqual(floor(2), 2)
     self.assertEqual(floor(12.32904), 12)
     self.assertEqual(floor(22.7330), 22)
     self.assertEqual(floor('24.7'), 24)
     self.assertEqual(floor('26.7'), 26)
     self.assertEqual(floor(Decimal(29.45)), 29)
コード例 #7
0
ファイル: test_utils.py プロジェクト: britlog/frappe
	def test_floor(self):
		from decimal import Decimal
		self.assertEqual(floor(2),              2 )
		self.assertEqual(floor(12.32904),       12)
		self.assertEqual(floor(22.7330),        22)
		self.assertEqual(floor('24.7'),         24)
		self.assertEqual(floor('26.7'),         26)
		self.assertEqual(floor(Decimal(29.45)), 29)
コード例 #8
0
def apply_putaway_rule(doctype, items, company, sync=None, purpose=None):
    """ Applies Putaway Rule on line items.

            items: List of Purchase Receipt/Stock Entry Items
            company: Company in the Purchase Receipt/Stock Entry
            doctype: Doctype to apply rule on
            purpose: Purpose of Stock Entry
            sync (optional): Sync with client side only for client side calls
    """
    if isinstance(items, string_types):
        items = json.loads(items)

    items_not_accomodated, updated_table = [], []
    item_wise_rules = defaultdict(list)

    for item in items:
        if isinstance(item, dict):
            item = frappe._dict(item)

        source_warehouse = item.get("s_warehouse")
        serial_nos = get_serial_nos(item.get("serial_no"))
        item.conversion_factor = flt(item.conversion_factor) or 1.0
        pending_qty, item_code = flt(item.qty), item.item_code
        pending_stock_qty = flt(
            item.transfer_qty) if doctype == "Stock Entry" else flt(
                item.stock_qty)
        uom_must_be_whole_number = frappe.db.get_value('UOM', item.uom,
                                                       'must_be_whole_number')

        if not pending_qty or not item_code:
            updated_table = add_row(item, pending_qty, source_warehouse
                                    or item.warehouse, updated_table)
            continue

        at_capacity, rules = get_ordered_putaway_rules(
            item_code, company, source_warehouse=source_warehouse)

        if not rules:
            warehouse = source_warehouse or item.warehouse
            if at_capacity:
                # rules available, but no free space
                items_not_accomodated.append([item_code, pending_qty])
            else:
                updated_table = add_row(item, pending_qty, warehouse,
                                        updated_table)
            continue

        # maintain item/item-warehouse wise rules, to handle if item is entered twice
        # in the table, due to different price, etc.
        key = item_code
        if doctype == "Stock Entry" and purpose == "Material Transfer" and source_warehouse:
            key = (item_code, source_warehouse)

        if not item_wise_rules[key]:
            item_wise_rules[key] = rules

        for rule in item_wise_rules[key]:
            if pending_stock_qty > 0 and rule.free_space:
                stock_qty_to_allocate = flt(
                    rule.free_space) if pending_stock_qty >= flt(
                        rule.free_space) else pending_stock_qty
                qty_to_allocate = stock_qty_to_allocate / item.conversion_factor

                if uom_must_be_whole_number:
                    qty_to_allocate = floor(qty_to_allocate)
                    stock_qty_to_allocate = qty_to_allocate * item.conversion_factor

                if not qty_to_allocate:
                    break

                updated_table = add_row(item,
                                        qty_to_allocate,
                                        rule.warehouse,
                                        updated_table,
                                        rule.name,
                                        serial_nos=serial_nos)

                pending_stock_qty -= stock_qty_to_allocate
                pending_qty -= qty_to_allocate
                rule["free_space"] -= stock_qty_to_allocate

                if not pending_stock_qty > 0:
                    break

        # if pending qty after applying all rules, add row without warehouse
        if pending_stock_qty > 0:
            items_not_accomodated.append([item.item_code, pending_qty])

    if items_not_accomodated:
        show_unassigned_items_message(items_not_accomodated)

    items[:] = updated_table if updated_table else items  # modify items table

    if sync and json.loads(sync):  # sync with client side
        return items
コード例 #9
0
def calculate_monthly_ammount(ammount,
                              default_currency,
                              from_date,
                              to_date,
                              foreign_ammount,
                              foreign_currency=None,
                              filters=None):
    float_precision = cint(frappe.db.get_default("float_precision")) or 2
    months_report_list = []
    for month in get_months(filters['from_date'], filters['to_date']):
        months_report_list.append("{0} {1}".format(month.lower(),
                                                   default_currency))
        if filters.get("foreign_currency") and filters.get(
                "foreign_currency") != default_currency:
            months_report_list.append("{0} {1}".format(
                month.lower(), filters.get("foreign_currency")))
    if ammount and from_date and to_date:
        monthly_ammount_obj = {}
        days = 0
        date = from_date
        end_date = to_date
        field_list = []
        field_list_foreign = []
        first_last = 0
        first_last_foreign = 0
        sub_ammount = 0
        sub_ammount_foreign = 0
        # days_list= []

        while date <= end_date:
            start_month = getdate(date).month
            end_month = getdate(to_date).month

            if start_month == end_month:
                last_day = end_date
                days_diff = date_diff(last_day, date) + 1
                if check_full_month(date, last_day):
                    days_diff = 30
                days += days_diff
                # days_list.append(days_diff)
                if date == last_day:
                    last_day = add_days(last_day, 1)
                month_filed = (get_months(str(date), str(last_day))[0]).lower()
                month_len = date_diff(get_last_day(date), get_first_day(date))
                field_list.append({
                    "days_diff":
                    days_diff,
                    "month_filed":
                    "{0} {1}".format(month_filed, default_currency),
                    "month_len":
                    month_len,
                    "foreign":
                    False,
                })
                if foreign_currency and foreign_currency != default_currency:
                    field_list_foreign.append({
                        "days_diff":
                        days_diff,
                        "month_filed":
                        "{0} {1}".format(month_filed, foreign_currency),
                        "month_len":
                        month_len,
                        "foreign":
                        True,
                    })
                date = get_first_day(add_months(date, 1))

            else:
                last_day = get_last_day(date)
                days_diff = date_diff(last_day, date) + 1
                if check_full_month(date, last_day):
                    days_diff = 30
                days += days_diff
                # days_list.append(days_diff)
                if date == last_day:
                    last_day = add_days(last_day, 1)
                month_filed = (get_months(str(date), str(last_day))[0]).lower()
                month_len = date_diff(get_last_day(date), get_first_day(date))
                field_list.append({
                    "days_diff":
                    days_diff,
                    "month_filed":
                    "{0} {1}".format(month_filed, default_currency),
                    "month_len":
                    month_len,
                    "foreign":
                    False,
                })
                if foreign_currency and foreign_currency != default_currency:
                    field_list_foreign.append({
                        "days_diff":
                        days_diff,
                        "month_filed":
                        "{0} {1}".format(month_filed, foreign_currency),
                        "month_len":
                        month_len,
                        "foreign":
                        True,
                    })
                date = get_first_day(add_months(date, 1))

        if floor(days / 30) != (days / 30) and (floor(days / 30) * 30 +
                                                6) < days:
            days = (floor(days / 30) + 1) * 30
        elif floor(days / 30) != (days / 30) and floor(days / 30) * 30 < days:
            days = floor(days / 30) * 30

        daily_ammount = ammount / (days)
        daily_ammount_foreign = foreign_ammount / (days)

        m = 1
        for i in field_list:
            if m == 1 and i["days_diff"] < 30:
                first_last += i["days_diff"]
            elif m == len(field_list) and i["days_diff"] < 30:
                first_last += i["days_diff"]
            else:
                sub_ammount += i["days_diff"] * daily_ammount
            m += 1

        m = 1
        for i in field_list_foreign:
            if m == 1 and i["days_diff"] < 30:
                first_last_foreign += i["days_diff"]
            elif m == len(field_list) and i["days_diff"] < 30:
                first_last_foreign += i["days_diff"]
            else:
                sub_ammount_foreign += i["days_diff"] * daily_ammount_foreign
            m += 1

        n = 1
        for i in field_list_foreign:
            if n == 1 and i["days_diff"] < 30:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] *
                    ((foreign_ammount - sub_ammount_foreign) / first_last),
                    float_precision)
            elif n == len(field_list) and i["days_diff"] < 30:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] *
                    ((foreign_ammount - sub_ammount_foreign) / first_last),
                    float_precision)
            else:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] * daily_ammount_foreign, float_precision)
            n += 1

        n = 1
        for i in field_list:
            if n == 1 and i["days_diff"] < 30:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] * ((ammount - sub_ammount) / first_last),
                    float_precision)
            elif n == len(field_list) and i["days_diff"] < 30:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] * ((ammount - sub_ammount) / first_last),
                    float_precision)
            else:
                monthly_ammount_obj[i["month_filed"]] = flt(
                    i["days_diff"] * daily_ammount, float_precision)
            n += 1
        advance_before = 0
        advance_after = 0
        first_month = datetime.strptime(
            months_report_list[0][:6].replace("-", " 20"), "%b %Y")
        last_month = datetime.strptime(
            months_report_list[-1][:6].replace("-", " 20"), "%b %Y")
        for key, value in monthly_ammount_obj.items():
            key_currency = key[7:]
            currency = foreign_currency or default_currency
            if key not in months_report_list and key_currency == currency:
                mydate = datetime.strptime(
                    str(key)[:6].replace("-", " 20"), "%b %Y")
                if mydate > last_month:
                    advance_after += value
                elif mydate < first_month:
                    advance_before += value
        if advance_after:
            monthly_ammount_obj["advance_after"] = advance_after
        if advance_before:
            monthly_ammount_obj["advance_before"] = advance_before
        return monthly_ammount_obj