from .finance_markup_price import markup_price from .finance_tax_add_vat import add_vat from .hospitality_gross_profit_menu_menu_gross_profit import menu_gross_profit from .hospitality_gross_profit_menu_types import MenuGrossProfit from .math_round_div import round_div from .money_amount import Money, money def menu_price_for_gp( cost: Money, target_gp_basis_points: int, price_step: int, jurisdiction: str, category: str, on_date: str, ) -> MenuGrossProfit: """The menu price that reaches a target GP. The net price is the smallest that makes the target on the VAT-exclusive price (finance.markup-price, rounded up), VAT goes on top, and the menu price is rounded up to the step a menu is printed in. Rounding only ever goes up, so the GP returned is never below the target. """ t = target_gp_basis_points if isinstance(t, bool) or not isinstance(t, int) or t < 0 or t > 9999: raise ValueError("targetGpBasisPoints must be a whole number from 0 to 9999, received %s" % (t,)) if isinstance(price_step, bool) or not isinstance(price_step, int) or price_step < 1: raise ValueError("priceStep must be at least 1, received %s" % (price_step,)) if cost.minor < 0: raise ValueError("cost must not be negative, received %d" % (cost.minor,)) net = markup_price(cost, t, "margin", "up") gross = add_vat(net, jurisdiction, category, on_date).gross menu_price = money(round_div(gross.minor, price_step, "up") * price_step, gross.currency) return menu_gross_profit(cost, menu_price, jurisdiction, category, on_date)