Commit 87be239f authored by Romain Courteaud's avatar Romain Courteaud 🐙

slapos_accounting:

* configure Sale Supply predicate
* test Supply Line matching and getPrice
* allow Supply Line to define price even if resource has variations
  Force quantity unit to match (no convertion for now)
* order Supply Predicate matching
* Supply Cell before Line
parent 34bc30c7
......@@ -6,11 +6,13 @@ def sort_key_method(e):
having source_function only
others
"""
return 0
parent = e.getParentValue()
if parent.getPortalType().endswith('Line'):
parent = parent.getParentValue()
return 0 - 1 * int(parent.hasSourceFunction()) - 2 * int(parent.hasGroup())
minus = 0.5
else:
minus = 0
return 0 - 1 * int(parent.hasDestination()) - minus
def filter_method(currency, destination_project, group):
def filter_by_source_function_and_group(l):
......@@ -38,6 +40,7 @@ def filter_method(currency, destination_project, group):
#if parent.getGroup() not in (None, group):
# continue
ret.append(i)
return ret
return filter_by_source_function_and_group
source = context.getSourceValue()
......@@ -47,13 +50,6 @@ else:
group = source.getGroup()
kw['filter_method'] = filter_method(context.getPriceCurrency(), context.getDestinationProject(), group)
"""
def filter_couscous(predicate_list):
raise NotImplementedError(predicate_list)
return predicate_list
kw['filter_method'] = filter_couscous
"""
kw['sort_key_method'] = sort_key_method
resource = context.getResourceValue()
......@@ -63,7 +59,6 @@ if resource is not None:
if product_line:
kw['categories'] = kw.get('categories', []) + ['product_line/%s' % product_line]
#raise NotImplementedError(str(kw))
return resource.getPriceCalculationOperandDict(
default=default, context=context, **kw)
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleSupplyCell_asPredicate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
parent = context.getParentValue()
if (parent.getPortalType() != 'Sale Supply') or (parent.getValidationState() != 'validated'):
# If this supply line is not in a validated Sale Supply, it does not apply.
if (not context.hasBasePrice()) or (not context.getPriceCurrency()) or (not context.getResource()) or (not context.getQuantityUnit()):
# Meaningless path if no resource/price_currency/base_price/quantity_unit
return None
supply = context.getParentValue()
base_category_tuple = ['resource', 'price_currency', 'quantity_unit']
if context.getPortalType() == 'Sale Supply Cell':
base_category_tuple.extend(supply.getVariationRangeBaseCategoryList())
supply = supply.getParentValue()
base_category_tuple = ('resource', 'price_currency')
if (supply.getPortalType() != 'Sale Supply') or (supply.getValidationState() != 'validated'):
# If this supply line is not in a validated Sale Supply, it does not apply.
return None
if context.getSourceSection():
base_category_tuple += ('source_section',)
base_category_tuple.append('source_section')
if context.getDestinationSection():
base_category_tuple += ('destination_section',)
base_category_tuple.append('destination_section')
if context.getSource():
base_category_tuple += ('source',)
base_category_tuple.append('source')
if context.getDestination():
base_category_tuple += ('destination',)
base_category_tuple.append('destination')
if context.getSourceProject():
base_category_tuple += ('source_project',)
base_category_tuple.append('source_project')
if context.getDestinationProject():
base_category_tuple += ('destination_project',)
base_category_tuple.append('destination_project')
#backwards compatibility
mapped_value_property_list = context.getMappedValuePropertyList()
......
......@@ -54,7 +54,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupplyLine_asPredicate</string> </value>
<value> <string>SaleSupplyLine_asPredicate</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -21,7 +21,8 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
# - one with 2 releases and 2 types
simple_product = self.portal.software_product_module.newContent(
portal_type="Software Product",
title="Simple Product"
title="Simple Product",
quantity_unit='time/month',
)
simple_product.newContent(
portal_type="Software Product Type Variation",
......@@ -34,7 +35,8 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
complex_product = self.portal.software_product_module.newContent(
portal_type="Software Product",
title="Complex Product"
title="Complex Product",
quantity_unit='time/month',
)
complex_product.newContent(
portal_type="Software Product Type Variation",
......@@ -61,28 +63,70 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
# - one for everybody (no destination)
# - one for one specific user
now = DateTime()
wrong_currency_supply = self.portal.sale_supply_module.newContent(
title="Wrong currency Supply",
start_date_range_min=now,
destination_project_value=project_1,
price_currency="currency_module/CNY",
)
everybody_supply = self.portal.sale_supply_module.newContent(
title="Everybody Supply",
start_date_range_min=now,
destination_project_value=project_1
destination_project_value=project_1,
price_currency="currency_module/EUR",
)
person_1_supply = self.portal.sale_supply_module.newContent(
title="Person 1 Supply",
start_date_range_min=now,
destination_project_value=project_1,
destination_value=person_1
destination_value=person_1,
price_currency="currency_module/EUR"
)
# Create sale Line/Cell for all product combination
sale_supply_cell_list = []
sale_supply_line_list = []
base_id = 'path'
for sale_supply in [everybody_supply, person_1_supply]:
base_price = 0
for sale_supply in [wrong_currency_supply, everybody_supply, person_1_supply]:
base_price += 1
sale_supply_line = sale_supply.newContent(
title="without resource",
portal_type="Sale Supply Line",
base_price=base_price,
)
sale_supply_line_list.append(sale_supply_line)
for software_product in [simple_product, complex_product]:
sale_supply_line = sale_supply.newContent(
title="%s without price" % software_product.getTitle(),
portal_type="Sale Supply Line",
resource_value=software_product
resource_value=software_product,
quantity_unit=software_product.getQuantityUnit(),
)
sale_supply_line_list.append(sale_supply_line)
base_price += 1
sale_supply_line = sale_supply.newContent(
title="%s without variation" % software_product.getTitle(),
portal_type="Sale Supply Line",
resource_value=software_product,
base_price=base_price,
quantity_unit=software_product.getQuantityUnit(),
)
sale_supply_line_list.append(sale_supply_line)
sale_supply_line = sale_supply.newContent(
title="%s with variation" % software_product.getTitle(),
portal_type="Sale Supply Line",
resource_value=software_product,
quantity_unit=software_product.getQuantityUnit(),
)
sale_supply_line_list.append(sale_supply_line)
base_price += 1
sale_supply_line.edit(
base_price=base_price,
p_variation_base_category_list=sale_supply_line.getVariationRangeBaseCategoryList()
)
sale_supply_line.setCellRange(
......@@ -95,9 +139,10 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
portal_type='Sale Supply Cell',
*cell_key
)
base_price += 1
sale_supply_cell.edit(
mapped_value_property_list=['allocable'],
allocable=True,
mapped_value_property_list=['base_price'],
base_price=base_price,
predicate_category_list=cell_key,
variation_category_list=cell_key
)
......@@ -105,7 +150,7 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
sale_supply.validate()
self.tic()
# Create 2 movements
# Create movements
# one for everybody
# one for one specific user
# check if predicates match
......@@ -122,14 +167,46 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
portal_type='Movement',
temp_object=1,
resource_value=software_product,
quantity_unit=software_product.getQuantityUnit(),
software_type_value=software_type,
software_release_value=software_release,
start_date=start_date,
destination_project_value=project,
destination_value=destination
destination_value=destination,
price_currency="currency_module/EUR"
)
# Check Sale Supply Cell predicate configuration
for sale_supply_line in sale_supply_line_list:
expected_test_result = (
(sale_supply_line.hasBasePrice()) and
(sale_supply_line.getPriceCurrency() == "currency_module/EUR") and
(software_product.getRelativeUrl() == sale_supply_line.getResource()) and
(project == sale_supply_line.getParentValue().getDestinationProjectValue()) and
((sale_supply_line.getParentValue().getDestinationValue() is None) or
(destination == sale_supply_line.getParentValue().getDestinationValue())) and
(start_date == sale_supply_line.getParentValue().getStartDateRangeMin())
)
assert sale_supply_line.test(tmp_context) == expected_test_result, """Expected: %s %i %s
Product: %s %s
Project: %s %s
Destination: %s %s
Date: %s %s
""" % (
expected_test_result, i, sale_supply_line.getRelativeUrl(),
software_product.getRelativeUrl(), sale_supply_line.getResource(),
project.getRelativeUrl(), sale_supply_line.getParentValue().getDestinationProject(),
destination, sale_supply_line.getParentValue().getDestination(),
start_date, sale_supply_line.getParentValue().getStartDateRangeMin()
)
assert (sale_supply_line in domain_tool.searchPredicateList(
tmp_context, portal_type=['Sale Supply Line'])) == expected_test_result
# Check Sale Supply Cell predicate configuration
for sale_supply_cell in sale_supply_cell_list:
expected_test_result = (
(sale_supply_cell.hasBasePrice()) and
(sale_supply_cell.getPriceCurrency() == "currency_module/EUR") and
(software_product.getRelativeUrl() == sale_supply_cell.getResource()) and
(software_type.getRelativeUrl() == sale_supply_cell.getSoftwareType()) and
(software_release.getRelativeUrl() == sale_supply_cell.getSoftwareRelease()) and
......@@ -138,7 +215,7 @@ class TestSlapOSSaleSupply(SlapOSTestCaseMixin):
(destination == sale_supply_cell.getParentValue().getParentValue().getDestinationValue())) and
(start_date == sale_supply_cell.getParentValue().getParentValue().getStartDateRangeMin())
)
assert sale_supply_cell.test(tmp_context) == expected_test_result, """Expected: %s %i
assert sale_supply_cell.test(tmp_context) == expected_test_result, """Expected: %s %i %s
Product: %s %s
Type: %s %s
Release: %s %s
......@@ -146,14 +223,67 @@ Project: %s %s
Destination: %s %s
Date: %s %s
""" % (
expected_test_result, i,
expected_test_result, i, sale_supply_cell.getRelativeUrl(),
software_product.getRelativeUrl(), sale_supply_cell.getResource(),
software_type.getRelativeUrl(), sale_supply_cell.getSoftwareType(),
software_release.getRelativeUrl(), sale_supply_cell.getSoftwareRelease(),
project.getRelativeUrl(),sale_supply_cell.getParentValue().getParentValue().getDestinationProject(),
project.getRelativeUrl(), sale_supply_cell.getParentValue().getParentValue().getDestinationProject(),
destination, sale_supply_cell.getParentValue().getParentValue().getDestination(),
start_date, sale_supply_cell.getParentValue().getParentValue().getStartDateRangeMin()
)
assert (sale_supply_cell in domain_tool.searchPredicateList(
tmp_context, portal_type=['Sale Supply Cell'])) == expected_test_result
i += 1
# New variation, to check the price when not Sale Supply Cell matching
with_price_software_release = simple_product.contentValues(portal_type="Software Product Release Variation")[0]
without_price_software_release = simple_product.newContent(
portal_type="Software Product Release Variation",
url_string="http://example.org/release_XX"
)
software_type = simple_product.contentValues(portal_type="Software Product Type Variation")[0]
# Create movements
# check getPrice
for destination, project, software_release, date, expected_price in [
(person_1, project_1, with_price_software_release, now, 24),
(person_1, project_1, without_price_software_release, now, 22),
(person_2, project_1, with_price_software_release, now, 14),
(person_2, project_1, without_price_software_release, now, 12),
(person_1, project_1, with_price_software_release, now - 1, None),
(person_1, project_2, without_price_software_release, now, None),
]:
resource_vcl = [
'software_release/%s' % software_release.getRelativeUrl(),
'software_type/%s' % software_type.getRelativeUrl()
]
resource_vcl.sort()
tmp_context = self.portal.portal_trash.newContent(
portal_type='Sale Order Line',
temp_object=1,
resource_value=simple_product,
variation_category_list=resource_vcl,
start_date=date,
destination_project_value=project,
destination_value=destination,
quantity_unit=software_product.getQuantityUnit(),
price_currency="currency_module/EUR"
)
tmp_context = tmp_context.newContent(
portal_type='Sale Order Cell',
temp_object=1,
software_type_value=software_type,
software_release_value=software_release
)#"""
# Check that price is the predicate base price
assert tmp_context.getPrice() == expected_price, """Expected:
Price: %s %s
Destination: %s
Project: %s
Software_release: %s
Date: %s
""" % (
tmp_context.getPrice(), expected_price,
destination, project, software_release, date
)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment