Commit 06801e83 authored by Romain Courteaud's avatar Romain Courteaud 🐙

slapos_accounting:

* add SlapOSLedgerConstraint
* add SlapOSLedgerConstraint on all * Transaction
  XXX FOrces tests to fail as much as possible if ledger is not configured.
  Add test to ensure constraint is configured
* hardcode automated ledger category for the newly created sale packing list
* propagate ledger in the simulation tree
* build ledger category from delivery builders
* aggregate ledger from order builder
* ensure ledger category is allowed on the portal type when using the constraint
* requires ledger on Hosting Subscription, Open Sale Order and Sale Packing List
* hardcode ledger value on Open Sale Order and Hosting Subscription
* open order must propagate the ledger value
* automated ledger path
* add ledger to the accounting template
* source_administration is not used anymore on Compute Node
* source_administration is not used anymore on Compute Node
parent 73aff586
......@@ -95,6 +95,7 @@
<string>resource/currency_module/EUR</string>
<string>payment_mode/payzen</string>
<string>specialise/sale_trade_condition_module/slapos_aggregated_trade_condition</string>
<string>ledger/automated</string>
</tuple>
</value>
</item>
......
......@@ -45,6 +45,7 @@
<string>price_currency</string>
<string>source_decision</string>
<string>destination_decision</string>
<string>ledger</string>
</tuple>
</value>
</item>
......
......@@ -42,6 +42,7 @@
<string>source_section</string>
<string>destination_section</string>
<string>price_currency</string>
<string>ledger</string>
</tuple>
</value>
</item>
......
......@@ -45,6 +45,7 @@
<string>destination_decision</string>
<string>price_currency</string>
<string>specialise</string>
<string>ledger</string>
</tuple>
</value>
</item>
......
......@@ -44,6 +44,7 @@
<string>source_section</string>
<string>specialise</string>
<string>causality</string>
<string>ledger</string>
</tuple>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Copy_or_Move_Permission</string> </key>
<value>
<list>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
<string>Authenticated</string>
<string>Owner</string>
</list>
</value>
</item>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>divergence_provider</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>matching_provider</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Divergence Tester" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_tester</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Divergence Tester</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value> <string>ledger</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ledger divergence tester</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<tuple>
<global name="PersistentMapping" module="Persistence.mapping"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<property_sheet_list>
<portal_type id="Accounting Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Amortisation Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Balance Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Cloud Contract">
<item>SlapOSCloudContractAccounting</item>
</portal_type>
......@@ -10,18 +19,31 @@
</portal_type>
<portal_type id="Hosting Subscription">
<item>SlapOSAccountingHostingSubscriptionConstraint</item>
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Internal Invoice Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Open Sale Order">
<item>SlapOSAccountingOpenSaleOrderConstraint</item>
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Open Sale Order Line">
<item>SlapOSAccountingOpenSaleOrderLineConstraint</item>
</portal_type>
<portal_type id="Payment Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Purchase Invoice Transaction">
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Sale Invoice Transaction">
<item>SlapOSAccountingSaleInvoiceTransactionConstraint</item>
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Sale Packing List">
<item>SlapOSAccountingSalePackingListConstraint</item>
<item>SlapOSLedgerConstraint</item>
</portal_type>
<portal_type id="Sale Packing List Line">
<item>SlapOSAccountingSalePackingListLineConstraint</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Sheet" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Require a portal type to have a ledger configured to prevent conflict between the automated and manual document handling.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SlapOSLedgerConstraint</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Sheet</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Membership Arity Constraint" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>constraint_base_category</string> </key>
<value>
<tuple>
<string>ledger</string>
</tuple>
</value>
</item>
<item>
<key> <string>constraint_portal_type</string> </key>
<value> <string>python: (\'Category\',)</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Require to configure one ledger.\n
\n
XXX maybe minimum value should be zero?\n
Let\'s try first like this to detect all issues in tests</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_arity_constraint_constraint</string> </value>
</item>
<item>
<key> <string>max_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>min_arity</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Membership Arity Constraint</string> </value>
</item>
<item>
<key> <string>use_acquisition</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ledger_category</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -26,7 +26,8 @@ def newOpenOrder():
activate_kw=activate_kw,
destination=person.getRelativeUrl(),
destination_decision=person.getRelativeUrl(),
title="%s SlapOS Subscription" % person.getTitle()
title="%s SlapOS Subscription" % person.getTitle(),
ledger_value=portal.portal_categories.ledger.automated,
)
new_open_sale_order.order(activate_kw=activate_kw)
......@@ -71,7 +72,8 @@ if instance_tree.getCausalityState() == 'diverged':
hosting_subscription = portal.hosting_subscription_module.newContent(
portal_type="Hosting Subscription",
title=instance_tree.getTitle()
title=instance_tree.getTitle(),
ledger_value=portal.portal_categories.ledger.automated,
)
hosting_subscription.validate()
start_date = hosting_subscription.HostingSubscription_calculateSubscriptionStartDate()
......
......@@ -69,6 +69,7 @@ for movement in movement_list:
source_section=movement.getSourceSection(),
destination_section=movement.getDestination(),
destination_decision=movement.getDestination(),
ledger=movement.getLedger(),
specialise=specialise,
price_currency=movement.getPriceCurrency(),
start_date=movement.getStartDate(),
......
......@@ -14,7 +14,9 @@ def newPackingList(movement, causality, message):
specialise=movement.getSpecialise(),
price_currency=movement.getPriceCurrency(),
causality=causality,
start_date=movement.getStartDate())
start_date=movement.getStartDate(),
ledger=movement.getLedger(),
)
delivery.confirm(message)
return delivery
......
......@@ -35,7 +35,7 @@ else:
# informative.
if compute_node.getReference() == reference:
aggregate_value_list = [compute_node]
person = compute_node.getSourceAdministrationValue(portal_type="Person")
person_relative_url = None
project = compute_node_project
else:
project = None # For now, else we should calculate this too.
......@@ -71,6 +71,7 @@ else:
portal_type="Person")
except:
raise ValueError(instance.getRelativeUrl())
person_relative_url = person.getRelativeUrl()
aggregate_value_list = [partition, instance, subscription]
......@@ -79,21 +80,20 @@ else:
quantity=movement['quantity'],
aggregate_value_list=aggregate_value_list,
resource=movement['resource'],
person=person.getRelativeUrl(),
person=person_relative_url,
project=project
)
)
# Time to create the PL
person = compute_node.getSourceAdministrationValue(portal_type="Person")
delivery_template = portal.restrictedTraverse(
portal.portal_preferences.getPreferredInstanceDeliveryTemplate())
delivery = delivery_template.Base_createCloneDocument(batch_mode=1)
delivery.edit(
title=delivery_title,
destination=person.getRelativeUrl(),
destination_decision=person.getRelativeUrl(),
#destination=person.getRelativeUrl(),
#destination_decision=person.getRelativeUrl(),
start_date=context.getCreationDate(),
)
......
Accounting Transaction | SlapOSLedgerConstraint
Amortisation Transaction | SlapOSLedgerConstraint
Balance Transaction | SlapOSLedgerConstraint
Cloud Contract Line | SlapOSCloudContractLineAccounting
Cloud Contract | SlapOSCloudContractAccounting
Computer Consumption TioXML File | SortIndex
Hosting Subscription | SlapOSAccountingHostingSubscriptionConstraint
Hosting Subscription | SlapOSLedgerConstraint
Internal Invoice Transaction | SlapOSLedgerConstraint
Open Sale Order Line | SlapOSAccountingOpenSaleOrderLineConstraint
Open Sale Order | SlapOSAccountingOpenSaleOrderConstraint
Open Sale Order | SlapOSLedgerConstraint
Payment Transaction | SlapOSLedgerConstraint
Purchase Invoice Transaction | SlapOSLedgerConstraint
Sale Invoice Transaction | SlapOSAccountingSaleInvoiceTransactionConstraint
Sale Invoice Transaction | SlapOSLedgerConstraint
Sale Packing List Line | SlapOSAccountingSalePackingListLineConstraint
Sale Packing List | SlapOSAccountingSalePackingListConstraint
Sale Packing List | SlapOSLedgerConstraint
Slave Instance | InstanceAccountingSynchronisation
Software Instance | InstanceAccountingSynchronisation
User Consumption HTML File | SortIndex
\ No newline at end of file
InstanceAccountingSynchronisation
SlapOSLedgerConstraint
SlapOSAccountingOpenSaleOrderLineConstraint
SlapOSAccountingOpenSaleOrderConstraint
SlapOSAccountingHostingSubscriptionConstraint
......
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