From 95a264af9938b4f5843016df0376048ab83ade11 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 31 Oct 2019 14:16:22 +0100 Subject: [PATCH] P5-4394 add framed-prints price formulas --- api/lib/prices.py | 44 ++++++++++++++++++++++++++++++++++ api/resources/prices.py | 34 ++++++++++++++++++++++++++ docs/prices.md | 28 ++++++++++++++++++++++ tests/lib/test_prices.py | 18 ++++++++++++++ tests/resources/test_prices.py | 8 +++++++ 5 files changed, 132 insertions(+) diff --git a/api/lib/prices.py b/api/lib/prices.py index 2b82d6d..dd0b848 100644 --- a/api/lib/prices.py +++ b/api/lib/prices.py @@ -296,6 +296,50 @@ def _price_for_poster_hanger_size(size): raise ValueError("Invalid poster hanger size: {}".format(size)) +def framed_print_price( + sku, market, designer=None, reseller=None, inquiry=None, rounded=True, inc_vat=True +): + sku_prices = { + "GLOBAL-CFP-12x12": 446, + "GLOBAL-CFP-11x14": 478, + "GLOBAL-CFP-12x16": 494, + "GLOBAL-CFP-16x20": 574, + "GLOBAL-CFP-20x20": 690, + "GLOBAL-CFP-18x24": 708, + "GLOBAL-CFP-20x28": 761, + "GLOBAL-CFP-24x32": 831, + "GLOBAL-CFP-28x28": 867, + "GLOBAL-CFP-24x36": 1035, + "GLOBAL-CFP-28x40": 1127, + } + + if not sku in sku_prices: + raise ValueError("Invalid SKU number: {}".format(sku)) + + price = sku_prices[sku] + + price *= market.price_adjustments + + if designer: + price *= (float(designer.pricepremium) / 100) + 1 + + if reseller: + price *= (float(reseller.pricepremium) / 100) + 1 + + if inquiry: + price *= (float(inquiry.pricepremium) / 100) + 1 + + price *= market.exchange_rate + + if inc_vat: + price *= market.vat + + if rounded: + price = round_half_up(price) + + return price + + def inquiry_price( inquiry, inc_price_retouch=True, rounded=True, inc_vat=True, **kwargs ): diff --git a/api/resources/prices.py b/api/resources/prices.py index 6e1fa15..1218157 100644 --- a/api/resources/prices.py +++ b/api/resources/prices.py @@ -11,6 +11,7 @@ from api.lib.prices import ( canvas_frame_price, poster_price, poster_hanger_price, + framed_print_price, m2_price, inquiry_price, ) @@ -239,6 +240,39 @@ def poster_hanger(): return jsonify(data=data) +@mod.route("/framed-print", methods=["GET"]) +@validate_territory("territory") +def framed_print(): + sku = request.args.get("sku", type=str) + market = market_model.from_territory(request.args.get("territory")) + reseller = get_reseller() + designer = get_designer() + + data = [ + { + "sku": sku, + "price": framed_print_price( + sku, + market, + designer=designer, + reseller=reseller, + rounded=False, + inc_vat=True, + ), + "price_excl_vat": framed_print_price( + sku, + market, + designer=designer, + reseller=reseller, + rounded=False, + inc_vat=False, + ), + } + ] + + return jsonify(data=data) + + def get_inquiry_measurements(inquiry): """ this function returns width and height to be used in the price calculations """ diff --git a/docs/prices.md b/docs/prices.md index ab448b9..1373a25 100644 --- a/docs/prices.md +++ b/docs/prices.md @@ -124,6 +124,34 @@ Sample response } ``` +## Calculate framed print price + +Calculate price inc VAT of a framed print product. + +| Parameter | Description | +| --------- | ------------| +| `sku` | Pwinty SKU number | +| `territory` | Two letter iso code e.g `SE`. Territory affect the price in different ways like VAT, currency exchanges etc. | +| `dealerurl` | Optional parameter e.g `ackes`. Should always be used when calling the api from a dealerstore. If a dealerstore exists with this url additional fees will be applied to the price. | +| `product` | Optional parameter e.g `43894`. If a product with this id exists the api will calculate the price for the given product. | + +Sample request + +`curl -X GET 'https://api2.photowall.com/prices/framed-print?sku=GLOBAL-CFP-12x12&territory=SE` + +Sample response +``` +{ + "data": [ + { + "price": 557.5, + "price_excl_vat": 446.0, + "sku": "GLOBAL-CFP-12x12" + } + ] +} +``` + ## Calculate "Do it yourself frame" price Calculate the price for the "do it yourself frame" (DIY). Note that width and height parameters may be adjusted if they go over or under the limits that are valid for a canvas-frame. The values that are used in the price-calculation are always returned in the response. diff --git a/tests/lib/test_prices.py b/tests/lib/test_prices.py index 340212a..cd2ca4c 100644 --- a/tests/lib/test_prices.py +++ b/tests/lib/test_prices.py @@ -543,3 +543,21 @@ class TestPrice(unittest2.TestCase): self.assertEqual( 250, inquiry_price(inquiry, inc_price_retouch=False, hanger=False) ) + + def test_framed_print_price(self): + self.assertEqual(558, framed_print_price(sku="GLOBAL-CFP-12x12", market=sweden)) + self.assertEqual( + 569, + framed_print_price( + sku="GLOBAL-CFP-12x12", market=sweden, designer=designer_moomin + ), + ) + self.assertEqual( + 528, framed_print_price(sku="GLOBAL-CFP-12x12", market=denmark) + ) + + def test_invalid_framed_print_code(self): + with self.assertRaises(ValueError) as context: + framed_print_price(sku="invalid", market=sweden) + + self.assertTrue("Invalid SKU number" in str(context.exception)) diff --git a/tests/resources/test_prices.py b/tests/resources/test_prices.py index 4727901..ea89eb2 100644 --- a/tests/resources/test_prices.py +++ b/tests/resources/test_prices.py @@ -201,3 +201,11 @@ class TestEndpoints(flask_testing.TestCase): response = self.client.get("/prices/inquiry/1?width=100&height=100") self.assert200(response) self.assertEqual("poster", response.json["group"]) + + def test_framed_print(self): + response = self.client.get( + "/prices/framed-print?sku=GLOBAL-CFP-12x12&territory=SE" + ) + self.assert200(response) + expected = [{"price": 557.5, "price_excl_vat": 446, "sku": "GLOBAL-CFP-12x12"}] + self.assertEqual(expected, response.json["data"])