Skip to content

Commit

Permalink
Add price_formula
Browse files Browse the repository at this point in the history
  • Loading branch information
MonsieurV committed Feb 10, 2023
1 parent d60e468 commit 35bbafb
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.6.0

* Add a parser option `options.price_formula.enabled` in definition to be set to `True` for allowing to set price as formula. The formula starts with `=` and follow with valid Python code. For eg. `prestations.0.price: =1000*0.7` will yield a price of 700 on the first prestation.

# 0.5.0

* Add a `rounding-decimals` kwarg to `parse_invoices` and `parse_quote`, which default to `2`
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def package_files(directory):

setup(
name="tqwgp-parser",
version="0.5.0",
version="0.6.0",
url="https://github.com/YtoTech/talk-quote-work-getpaid-parser",
license="AGPL-3.0",
author="Yoan Tournade",
Expand Down
19 changes: 19 additions & 0 deletions tests/test_definitions_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,25 @@ def test_parse_simple_quote_rounding():
assert quote["price"]["vat"] == 7465.87
assert quote["price"]["total_vat_incl"] == 44795.2

def test_parse_simple_quote_rounding():
"""
Prestation prices can include formulas. (opt-in)
"""
definition = copy.deepcopy(TESLA_16_01_QUOTE)
definition["options"] = {
**definition.get("options", {}),
"price_formula": {
"enabled": True
}
}
definition["prestations"][0]["price"] = "=1000*0.3"
quote = parse_quote(definition)
checkQuote(quote)
assert len(quote["prestations"]) == 4
assert quote["prestations"][0]["total"] == 300
assert quote["prestations"][0]["price"] == 300
assert quote["price"]["total_vat_excl"] == 35300.0


def test_parse_simple_quote_no_optional_tva():
"""
Expand Down
63 changes: 50 additions & 13 deletions tqwgp_parser/parser.hy
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,31 @@
(get (parse-all-prestations (get prestation "prestations") vat-rate options prestation) 0))
(.append sections (parse-section prestation section-prestations vat-rate options))
(.extend all-prestations section-prestations))
(.append all-prestations (parse-prestation prestation section))
(.append all-prestations (parse-prestation prestation section options))
)) prestation))
(, all-prestations sections))

(defn parse-prestation [prestation section]
(defn apply-any-price-formula [price price-formula]
(if (and
(get-in price-formula ["enabled"] False)
(string? price)
(= (get price 0) "="))
(eval (cut price 1 None))
price))

(defn parse-prestation [prestation section options]
(merge-dicts [
(parse-dict-values prestation
["title"]
["price" "quantity" "description" "batch" "optional"])
{
"total" (compute-price [prestation] :count-optional True)
"price" (apply-any-price-formula
(get-default prestation "price" None)
(get options "price_formula"))
"total" (compute-price [prestation]
:count-optional True
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
"quantity" (get-default prestation "quantity" 1)
"section" (get-default (if (none? section) {} section) "title" None)
"batch" (parse-batch (get-default prestation "batch" (get-default (if (none? section) {} section) "batch" None)))
Expand All @@ -54,18 +68,23 @@
"price" (compute-price-vat prestations
:count-optional False
:vat-rate vat-rate
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
"optional_price" (compute-price-vat prestations
:count-optional True
:vat-rate vat-rate
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
;; TODO Normalize batch here: only set if all section prestation has same batch
;; (alternative: set a list of batches).
"batch" (parse-batch (get-default section "batch" None))
"optional" (get-default section "optional" False)
}]))

(defn compute-price [prestations [count-optional False] [rounding-decimals None]]
(defn compute-price
[prestations
[count-optional False] [rounding-decimals None]
[price-formula {}]]
"""
Parse price of a flattened list of prestations
(actually any list with object containing a price property),
Expand All @@ -76,7 +95,7 @@
(rounded-number
(reduce
(fn [total prestation]
(setv price (get prestation "price"))
(setv price (apply-any-price-formula (get prestation "price") price-formula))
(setv add-price (and (numeric? price) (or count-optional (not (get-default prestation "optional" False)))))
(setv prestation-total (if (numeric? price) (* price (get-default prestation "quantity" 1))))
(cond
Expand All @@ -99,15 +118,19 @@
(simplest-numerical-format (* (/ vat-rate 100) price))
rounding-decimals))

(defn compute-price-vat [prestations [count-optional False] [vat-rate None] [rounding-decimals None]]
(defn compute-price-vat
[prestations
[count-optional False] [vat-rate None]
[rounding-decimals None] [price-formula {}]]
"""
Compute price, as an object including VAT component, total with VAT excluded, total with VAT included ;
from a list of objects containing a price (numerical) property.
"""
;; TODO Handle price object in element list, taking total_vat_excl for the summation?
(setv total-vat-excl (compute-price prestations
:count-optional count-optional
:rounding-decimals rounding-decimals))
:rounding-decimals rounding-decimals
:price-formula price-formula))
(if (numeric? vat-rate)
(do
(setv vat (if (none? total-vat-excl) None (compute-vat total-vat-excl vat-rate
Expand Down Expand Up @@ -209,6 +232,11 @@
"logo" (parse-logo (get-default sect "logo" None))
}]))

(defn parse-parser-options [definition]
{"price_formula" {
"enabled" (get-in definition ["options" "price_formula" "enabled"] False)
}})

(defn parse-quote [definition #** kwargs]
"""
Parse and normalize a quote definition.
Expand All @@ -218,6 +246,7 @@
"rounding-decimals" 2
}
kwargs
(parse-parser-options definition)
]))
(setv vat-rate (get-default definition "vat_rate" None))
(setv (, all-prestations sections)
Expand All @@ -235,7 +264,8 @@
"vat_rate" vat_rate
"price" (compute-price-vat all-prestations
:vat-rate vat-rate
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
;; Derive sections from all-prestations (and sections too).
"batches" (recompose-batches all-prestations)
"all_prestations" all-prestations
Expand All @@ -248,7 +278,8 @@
"optional_price" (compute-price-vat all-optional-prestations
:count-optional True
:vat-rate vat-rate
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
"display_project_reference" (none-or-true? (get-default definition "display_project_reference" True))
}]))

Expand All @@ -259,9 +290,13 @@
["description" "quantity"])
{
"quantity" (get-default line "quantity" 1)
"price" (apply-any-price-formula
(get-default line "price" None)
(get options "price_formula"))
"total" (compute-price [line]
:count-optional True
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
}
]))

Expand Down Expand Up @@ -290,7 +325,8 @@
"vat_rate" (get merged-invoice "vat_rate")
"price" (compute-price-vat lines
:vat-rate (get merged-invoice "vat_rate")
:rounding-decimals (get options "rounding-decimals"))
:rounding-decimals (get options "rounding-decimals")
:price-formula (get options "price_formula"))
"display_project_reference" (none-or-true? (get-default merged-invoice "display_project_reference" True))
}]))

Expand All @@ -303,6 +339,7 @@
"rounding-decimals" 2
}
kwargs
(parse-parser-options definition)
]))
(defn parse-invoice-closure [invoice]
(parse-invoice invoice definition options))
Expand Down
15 changes: 15 additions & 0 deletions tqwgp_parser/utils.hy
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
(defn numeric? [v]
(isinstance v (, int float)))

(defn string? [v]
(isinstance v (, str bytes)))

(defn none? [v]
(= v None))

Expand Down Expand Up @@ -68,6 +71,18 @@
(get value key)
default))

(defn get-in [value key-path default]
(setv current-key (if (= (len key-path) 0) None (get key-path 0)))
(if (none? current-key)
default
(if (in current-key value)
(if (= (len key-path) 1)
(get value current-key)
(get-in
(get value current-key)
(cut key-path 1 None)
default))
default)))

; Lists.

Expand Down

0 comments on commit 35bbafb

Please sign in to comment.