P5-2777 add poster price calculations

This commit is contained in:
Martin
2018-10-04 16:18:35 +02:00
parent c798a4da0b
commit 04187803af
5 changed files with 266 additions and 7 deletions
+102
View File
@@ -50,6 +50,7 @@ def wallpaper_price(width, height, material, market, designer=None, reseller=Non
if rounded:
price = round(price)
return price
@@ -75,6 +76,7 @@ def canvas_cm2_price(cm2):
cm2_price = price_cm2_at_10000cm2 - discount
cm2_price = max(cm2_price, 0.064)
return cm2_price
@@ -146,6 +148,106 @@ def canvas_frame_price(width, height, market, reseller=None, rounded=True, inc_v
return price
def poster_cm2_price(cm2):
price_cm2_at_1cm2 = 0.084
price_cm2_at_5000cm2 = 0.0392
price_cm2_at_10000cm2 = 0.0336
price_cm2_at_22500cm2 = 0.028
if cm2 <= 5000:
diff = price_cm2_at_1cm2 - price_cm2_at_5000cm2
discount = (diff / 5000) * cm2
cm2_price = price_cm2_at_1cm2 - discount
elif cm2 > 5000 and cm2 <= 10000:
diff = price_cm2_at_5000cm2 - price_cm2_at_10000cm2
discount = (diff / 5000) * (cm2 - 5000)
cm2_price = price_cm2_at_5000cm2 - discount
elif cm2 > 10000:
diff = price_cm2_at_10000cm2 - price_cm2_at_22500cm2
discount = (diff / 12500) * (cm2 - 10000)
cm2_price = price_cm2_at_10000cm2 - discount
cm2_price = max(cm2_price, 0.028)
return cm2_price
def poster_price(width, height, market, hanger=True, designer=None, reseller=None, inquiry=None, rounded=True, inc_vat=True):
cm2 = width * height
cm2_price = poster_cm2_price(cm2)
price = cm2 * cm2_price
price = max(price, 134.4) # the price can never go below 134.4 SEK
if(hanger):
price += _price_for_poster_hanger_size(width)
price *= market.price_adjustments
price += package_price(width, height, market)
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 poster_hanger_price(width, market, reseller=None, rounded=True, inc_vat=True):
"""calculates price for poster hanger only"""
price = _price_for_poster_hanger_size(width)
price += 50 # add 50 SEK extra since they are buying only the hanger
price *= market.price_adjustments
price += package_price(width, 10, market) # we assume the poster hanger has a height of 10cm here
if reseller:
price *= (float(reseller.pricepremium) / 100) + 1
price *= market.exchange_rate
if inc_vat:
price *= market.vat
if rounded:
price = round_half_up(price)
return price
def _price_for_poster_hanger_size(size):
if size > 0 and size <= 30:
return 95.2
if size > 30 and size <= 50:
return 135.2
if size > 50 and size <= 60:
return 143.2
if size > 60 and size <= 70:
return 151.2
if size > 70 and size <= 100:
return 220
if size > 100 and size <= 125:
return 250
if size > 125 and size <= 150:
return 300
raise ValueError('Invalid poster hanger size: {}'.format(size))
def inquiry_price(inquiry, inc_price_retouch=True, rounded=True, inc_vat=True, **kwargs):
width = kwargs.get('width', inquiry.width)
height = kwargs.get('height', inquiry.height)
+49 -2
View File
@@ -5,7 +5,15 @@ from api.models.inquiry import Inquiry
from api.models.product import Material, Product
from api.models.contract_customer import ContractCustomer
from api.models import market as market_model
from api.lib.prices import wallpaper_price, canvas_price, canvas_frame_price, m2_price, inquiry_price
from api.lib.prices import (
wallpaper_price,
canvas_price,
canvas_frame_price,
poster_price,
poster_hanger_price,
m2_price,
inquiry_price,
)
from api.lib.limits import calculate_canvas_limits
mod = Blueprint('prices', __name__, url_prefix='/prices')
@@ -70,7 +78,6 @@ def canvas():
request.args.get('height', type=int),
framed
)
# def canvas_price(width, height, market, framed=True, designer=None, reseller=None, inquiry=None, rounded=True, inc_vat=True):
data.append({
'framed': framed,
@@ -83,6 +90,30 @@ def canvas():
return jsonify(data=data)
@mod.route('/poster', methods=['GET'])
@validate_number('width', 'height')
@validate_territory('territory')
def poster():
width = request.args.get('width', type=int)
height = request.args.get('height', type=int)
market = market_model.from_territory(request.args.get('territory'))
reseller = get_reseller()
designer = get_designer()
data = []
for hanger in [True, False]:
data.append({
'hanger': hanger,
'width': width,
'height': height,
'price': poster_price(width, height, market, hanger=hanger, designer=designer, reseller=reseller, rounded=False, inc_vat=True),
'price_excl_vat': poster_price(width, height, market, hanger=hanger, designer=designer, reseller=reseller, rounded=False, inc_vat=False),
})
return jsonify(data=data)
@mod.route('/diy-frame', methods=['GET'])
@validate_number('width', 'height')
@validate_territory('territory')
@@ -104,6 +135,22 @@ def diy_frame():
return jsonify(data=data)
@mod.route('/poster-hanger', methods=['GET'])
@validate_number('width')
@validate_territory('territory')
def poster_hanger():
width = request.args.get('width', type=int)
market = market_model.from_territory(request.args.get('territory'))
reseller = get_reseller()
data = [{
'width': width,
'price': poster_hanger_price(width, market, reseller=reseller, rounded=False),
'price_excl_vat': poster_hanger_price(width, market, 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 """
+69 -4
View File
@@ -7,7 +7,7 @@ The prices resource provides a simple API to retrive price information about wal
Calculate price inc VAT of a wallpaper product. The response will contain prices for all available materials.
| Parameter | Description |
| --------- | -----| -------- | -
| --------- | ------------|
| `width` | Wallpaper width in cm e.g `100` |
| `height` | Wallpaper height in cm e.g `50` |
| `territory` | Two letter iso code e.g `SE`. Territory affect the price in different ways like VAT, currency exchanges etc. |
@@ -48,7 +48,7 @@ Sample response
Calculate price inc VAT of a canvas product. The response will contain information for both framed/not framed canvases. Note that width and height parameters may be adjusted if they go over or under the limits that are valid for a canvas. The values that are used in the price-calculation are always returned in the response.
| Parameter | Description |
| --------- | -----| -------- | -
| --------- | ------------|
| `width` | Canvas width in cm e.g `100` |
| `height` | Canvas height in cm e.g `50` |
| `territory` | Two letter iso code e.g `SE`. Territory affect the price in different ways like VAT, currency exchanges etc. |
@@ -86,13 +86,50 @@ Sample response
}
```
## Calculate poster price
Calculate price inc VAT of a poster product. The response will contain prices for both with and without hanger.
| Parameter | Description |
| --------- | ------------|
| `width` | Poster width in cm e.g `100` |
| `height` | Poster height in cm e.g `50` |
| `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/poster?width=50&height=30&territory=SE&product=46654`
Sample response
```
{
"data": [
{
"hanger": true,
"height": 30,
"price": 401.03000000000003,
"price_excl_vat": 320.824,
"width": 50
},
{
"hanger": false,
"height": 30,
"price": 199.92000000000002,
"price_excl_vat": 159.936,
"width": 50
}
]
}
```
## 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.
| Parameter | Description |
| --------- | -----| -------- | -
| --------- | ------------|
| `width` | Canvas width in cm e.g `100` |
| `height` | Canvas height in cm e.g `50` |
| `territory` | Two letter iso code e.g `SE`. Territory affect the price in different ways like VAT, currency exchanges etc. |
@@ -116,13 +153,41 @@ Sample response
}
```
## Calculate Poster hanger price
Calculate the price for a poster hanger
| Parameter | Description |
| --------- | ------------|
| `width` | Poster hanger width in cm e.g `100` |
| `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. |
Sample request
`curl -X GET 'https://api2.photowall.com/prices/poster-hanger?width=50&territory=SE`
Sample response
```
{
"data": [
{
"price": 231.5,
"price_excl_vat": 185.2,
"width": 50
}
]
}
```
## Calculate inquiry price
Calculates the price of an inquiry. For wallpapers inquiries the response will contain price information for all available materials and for canvas it will contain the price for both the framed and the not-framed canvas. The `group` attribute tells which kind of product you are dealing with.
The width and height stored on the inquiry will be used in the calculations by default. If you want to override these values you can send in your own width/height parameters in the request.
| Parameter | Description |
| --------- | -----| -------- | -
| --------- | ------------|
| `width` | Width in cm e.g `100`. Defaults to the inquiry stored width |
| `height` | Height in cm e.g `50`. Defaults to the inquiry stored height |
+16
View File
@@ -247,3 +247,19 @@ class TestPrice(unittest2.TestCase):
def test_package_price(self):
self.assertEqual(800, package_price(150, 40, market=us))
self.assertEqual(0, package_price(150, 40, market=sweden))
def test_poster_cm2_price(self):
self.assertEqual(0.08399104, poster_cm2_price(1))
self.assertEqual(0.08310400000000001, poster_cm2_price(100))
self.assertEqual(0.07504000000000001, poster_cm2_price(1000))
self.assertEqual(0.0336, poster_cm2_price(10000))
self.assertEqual(0.028, poster_cm2_price(100000))
def test_poster_price(self):
self.assertEqual(287, poster_price(width=30, height=40, hanger=True, market=sweden))
self.assertEqual(168, poster_price(width=30, height=40, hanger=False, market=sweden))
self.assertEqual(152, poster_price(width=125, height=40, market=us), 'extra cost for large packages')
def test_poster_hanger_price(self):
self.assertEqual(182, poster_hanger_price(30, market=sweden))
self.assertEqual(438, poster_hanger_price(150, market=sweden))
+29
View File
@@ -152,6 +152,35 @@ class TestEndpoints(flask_testing.TestCase):
self.assertEqual(50, product['height'])
self.assertAlmostEqual(731.25, product['price'], places=2)
def test_poster(self):
response = self.client.get('/prices/poster?width=50&height=30&territory=SE')
self.assert200(response)
expected = [
{
'hanger': True,
'height': 30,
'price': 337.0,
'price_excl_vat': 269.6,
'width': 50
},
{
'hanger': False,
'height': 30,
'price': 168.0,
'price_excl_vat': 134.4,
'width': 50
}
]
self.assertEqual(expected, response.json['data'])
def test_poster_hanger(self):
response = self.client.get('/prices/poster-hanger?width=50&territory=SE')
self.assert200(response)
product = response.json['data'][0]
self.assertEqual(231.5, product['price'])
self.assertEqual(185.2, product['price_excl_vat'])
self.assertEqual(50, product['width'])
def test_inquiry_wallpaper(self):
self._add_material('standard-wallpaper', 1, 236)
self._add_material('premium-wallpaper', 1, 260)