Commit c855235e authored by Łukasz Nowak's avatar Łukasz Nowak

Improve PayZen connection.

Generally allow customer to repay payment. The work was based on:

 * Start date do not have to be set during building.
 * Allow to reuse existing ID and allow PayZen to inform user, that transaction
   is already registered.
 * Do not create too many ids.
 * Drop not needed logging.
 * Be as precise as invoice's currency.
 * Consider all planned or confirmed transactions and take actions based on
   transaction status.
parent 9d6088c8
......@@ -83,7 +83,6 @@ if offset >= SQL_WINDOW_SIZE:\n
else:\n
limit = (0, SQL_WINDOW_SIZE)\n
\n
script.log(query_kw)\n
for computer_partition_candidate in context.portal_catalog(\n
limit=limit, **query_kw):\n
computer_partition_candidate = computer_partition_candidate.getObject() \n
......
......@@ -51,7 +51,6 @@
<item>
<key> <string>_body</string> </key>
<value> <string>from Products.ERP5Type.Message import translateString\n
from DateTime import DateTime\n
\n
payment_transaction = context\n
\n
......@@ -59,9 +58,6 @@ payment_transaction = context\n
if payment_transaction.getSimulationState() == "draft":\n
payment_transaction.plan(comment=translateString("Initialised by Delivery Builder."))\n
\n
if payment_transaction.getStartDate() is None:\n
payment_transaction.setStartDate(DateTime())\n
\n
# First set the payment transaction in the building state on the causality workflow\n
payment_transaction.startBuilding()\n
\n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Alarm" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_updatePayzenConfirmedPaymentTransaction</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>payzen_update_confirmed_payment_transaction</string> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_minute</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_minute_frequency</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>periodicity_month</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_month_day</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>periodicity_start_date</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1288051200.0</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>periodicity_week</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Alarm</string> </value>
</item>
<item>
<key> <string>sense_method_id</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Update status of confirmed Payment Transaction related with PayZen</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -8,7 +8,7 @@
<dictionary>
<item>
<key> <string>active_sense_method_id</string> </key>
<value> <string>Alarm_registerPlannedPaymentTransactionPayzen</string> </value>
<value> <string>Alarm_updatePayzenPaymentTransaction</string> </value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -22,7 +22,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>register_planned_payment_transaction_payzen</string> </value>
<value> <string>payzen_update_payment_transaction</string> </value>
</item>
<item>
<key> <string>periodicity_hour</string> </key>
......@@ -89,7 +89,7 @@
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Register planned Payment Transaction in payzen</string> </value>
<value> <string>Updates Payment Transactions accorind with PayZen interface</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -53,7 +53,7 @@
<value> <string>portal = context.getPortalObject()\n
portal.portal_catalog.searchAndActivate(\n
portal_type="Payment Transaction", \n
simulation_state="confirmed",\n
simulation_state=["planned", "confirmed"],\n
method_id=\'PaymentTransaction_updateStatus\',\n
packet_size=1, # just one to minimise errors\n
activate_kw={\'tag\': tag}\n
......@@ -67,7 +67,7 @@ context.activate(after_tag=tag).getId()\n
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_updatePayzenConfirmedPaymentTransaction</string> </value>
<value> <string>Alarm_updatePayzenPaymentTransaction</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>context.getPortalObject().portal_workflow.doActionFor(context, \'confirm_action\', comment=\'Transaction being registered in Payzen\')\n
<value> <string>context.getPortalObject().portal_workflow.doActionFor(context, \'confirm_action\', comment=\'Transaction synchronised with PayZen\')\n
</string> </value>
</item>
<item>
......
......@@ -50,24 +50,37 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
portal.portal_catalog.searchAndActivate(\n
portal_type="Payment Transaction", \n
simulation_state="planned",\n
method_id=\'PaymentTransaction_registerPayzen\',\n
packet_size=1, # just one to minimise errors\n
activate_kw={\'tag\': tag}\n
)\n
context.activate(after_tag=tag).getId()\n
<value> <string>from DateTime import DateTime\n
transaction = context\n
portal = transaction.getPortalObject()\n
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredPayzenIntegrationSite())\n
state_list = portal.getPortalCurrentInventoryStateList() + portal.getPortalTransitInventoryStateList()\n
previous_transaction = portal.portal_catalog.getResultValue(\n
destination_section_uid = transaction.getDestinationSectionUid(),\n
portal_type=transaction.getPortalType(),\n
simulation_state=state_list,\n
sort_on=((\'delivery.start_date\', \'DESC\'),),\n
limit=1,\n
)\n
\n
if previous_transaction is None:\n
return None\n
\n
previous_id = None\n
possible_previous_id = integration_site.getMappingFromCategory(\'causality/%s\' % previous_transaction.getRelativeUrl())\n
if possible_previous_id != \'Causality/%s\' % transaction.getRelativeUrl():\n
previous_id = possible_previous_id.split(\'/\')[1]\n
\n
return previous_id\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>tag, fixit, params</string> </value>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_registerPlannedPaymentTransactionPayzen</string> </value>
<value> <string>PaymentTransaction_getPreviousPayzenId</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,7 +50,9 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>context.getPortalObject().portal_workflow.doActionFor(context, \'start_action\', comment=\'Started automatically on Payzen Update\')\n
<value> <string>portal_workflow = context.getPortalObject().portal_workflow\n
if portal_workflow.isTransitionPossible(context, \'stopAction\'):\n
portal_workflow.doActionFor(context, \'stop_action\', comment=\'Transaction considered as paid by PayZen\')\n
</string> </value>
</item>
<item>
......@@ -59,7 +61,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaymentTransaction_start</string> </value>
<value> <string>PaymentTransaction_stop</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,11 +50,21 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
if context.getSimulationState() != \'confirmed\':\n
return\n
<value> <string>from DateTime import DateTime\n
portal = context.getPortalObject()\n
service = portal.portal_secure_payments.find()\n
portal.system_event_module.newContent(title=\'Transaction %s Payzen status update\' % context.getTitle(), portal_type=\'Payzen Event\', source_value=service, destination_value=context).updateStatus()\n
if context.getSimulationState() not in [\'planned\', \'confirmed\']:\n
return\n
\n
previous_id = context.PaymentTransaction_getPreviousPayzenId()\n
\n
if context.getSimulationState() == \'confirmed\' or previous_id is None:\n
portal.system_event_module.newContent(title=\'Transaction %s Payzen status update\' % context.getTitle(), portal_type=\'Payzen Event\', source_value=service, destination_value=context).updateStatus()\n
return\n
else:\n
context.setStartDate(DateTime())\n
context.updateCausalityState()\n
portal.system_event_module.newContent(title=\'Transaction %s Payzen registration\' % context.getTitle(), portal_type=\'Payzen Event\', source_value=service, destination_value=context).registerPayzen()\n
</string> </value>
</item>
<item>
......
......@@ -50,20 +50,24 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
if context.getSimulationState() != \'planned\':\n
return\n
service = portal.portal_secure_payments.find()\n
portal.system_event_module.newContent(title=\'Transaction %s Payzen registration\' % context.getTitle(), portal_type=\'Payzen Event\', source_value=service, destination_value=context).registerPayzen()\n
<value> <string>if simulation_state_list is None:\n
simulation_state_list = [\'planned\', \'confirmed\', \'started\', \'stopped\', \'delivered\']\n
person = context\n
\n
return context.portal_catalog.countResults(\n
portal_type=\'Payment Transaction\',\n
simulation_state=simulation_state_list,\n
default_destination_section_uid=person.getUid(),\n
)[0][0]\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
<value> <string>simulation_state_list=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaymentTransaction_registerPayzen</string> </value>
<value> <string>Person_countPayment</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -50,20 +50,17 @@
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>person = context.ERP5Site_getAuthenticatedMemberPersonValue()\n
\n
payment_amount = context.portal_catalog.countResults(\n
portal_type=\'Payment Transaction\',\n
default_destination_section_uid=person.getUid()\n
)[0][0]\n
<value> <string>person = context\n
\n
payment_transaction = context.portal_catalog.getResultValue(\n
portal_type=\'Payment Transaction\',\n
simulation_state=\'planned\',\n
default_destination_section_uid=person.getUid()\n
causality_state=\'solved\',\n
default_destination_section_uid=person.getUid(),\n
sort_on=((\'creation_date\', \'ASC\'), )\n
)\n
\n
if payment_amount == 1 and payment_transaction is not None and payment_transaction.getSimulationState() == \'planned\':\n
if payment_transaction is not None and payment_transaction.getSimulationState() in [\'planned\'] and payment_transaction.getCausalityState() in [\'solved\']:\n
return payment_transaction\n
return None\n
</string> </value>
......@@ -74,7 +71,7 @@ return None\n
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_getInitialPlannedPaymentTransaction</string> </value>
<value> <string>Person_getOutstandingPayment</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -97,10 +97,10 @@ if transaction_status in mark_transaction_id_list:\n
payzen_event.confirm()\n
payzen_event.acknowledge(comment=\'Automatic acknowledge as result of correct communication\')\n
if transaction.getSimulationState() == \'planned\':\n
transaction.activate().PaymentTransaction_confirm()\n
transaction.confirm()\n
\n
elif transaction_status in continue_transaction_id_list:\n
# Check authAmount and authDevise and if match, start transaction\n
# Check authAmount and authDevise and if match, stop transaction\n
auth_amount = int(data_kw[\'authAmount\'])\n
auth_devise = data_kw[\'authDevise\']\n
transaction_amount = int(round((transaction.PaymentTransaction_getTotalPayablePrice() * -100), 2))\n
......@@ -111,7 +111,9 @@ elif transaction_status in continue_transaction_id_list:\n
if transaction_devise != auth_devise:\n
payzen_event.confirm(comment=\'Received devise (%r) does not match stored on transaction (%r)\'% (auth_devise, transaction_devise))\n
return\n
transaction.activate().PaymentTransaction_start()\n
if transaction.getSimulationState() == \'planned\':\n
transaction.confirm()\n
transaction.PaymentTransaction_stop()\n
payzen_event.confirm()\n
payzen_event.acknowledge(comment=\'Automatic acknowledge as result of correct communication\')\n
else:\n
......
......@@ -60,26 +60,11 @@ payzen_event = state_change[\'object\']\n
transaction = payzen_event.getDestinationValue()\n
portal = transaction.getPortalObject()\n
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredPayzenIntegrationSite())\n
state_list = portal.getPortalCurrentInventoryStateList() + portal.getPortalTransitInventoryStateList()\n
service = portal.portal_secure_payments.find()\n
previous_transaction = portal.portal_catalog.getResultValue(\n
destination_section_uid = transaction.getDestinationSectionUid(),\n
portal_type=transaction.getPortalType(),\n
simulation_state=state_list,\n
sort_on=((\'delivery.start_date\', \'DESC\'),),\n
limit=1,\n
)\n
\n
if previous_transaction is None:\n
raise ValueError(\'It was not possible to find any previous transaction\')\n
\n
previous_id = None\n
possible_previous_id = integration_site.getMappingFromCategory(\'causality/%s\' % previous_transaction.getRelativeUrl())\n
if possible_previous_id != \'Causality/%s\' % transaction.getRelativeUrl():\n
previous_id = possible_previous_id.split(\'/\')[1]\n
\n
previous_id = transaction.PaymentTransaction_getPreviousPayzenId()\n
if previous_id is None:\n
raise ValueError(\'Transaction %s had not defined payzen integration\' % previous_transaction.getRelativeUrl())\n
raise ValueError(\'No previous id found\')\n
\n
previous_date, previous_id = previous_id.split(\'_\')\n
today = DateTime().toZone(\'UTC\').asdatetime().strftime(\'%Y%m%d\')\n
......
54
\ No newline at end of file
55
\ No newline at end of file
portal_alarms/payzen_update_confirmed_payment_transaction
portal_alarms/register_planned_payment_transaction_payzen
\ No newline at end of file
portal_alarms/payzen_update_payment_transaction
\ No newline at end of file
......@@ -55,6 +55,32 @@ from DateTime import DateTime\n
portal = context.getPortalObject()\n
service = portal.portal_secure_payments.find()\n
integration_site = portal.restrictedTraverse(portal.portal_preferences.getPreferredPayzenIntegrationSite())\n
\n
if context.getSimulationState() != \'planned\':\n
message = context.Base_translateString("Payment already registered.")\n
return context.getWebSiteValue().Base_redirect(keep_items={\'portal_status_message\': message})\n
\n
previous_id = context.PaymentTransaction_getPreviousPayzenId()\n
\n
now = DateTime()\n
today = now.toZone(\'UTC\').asdatetime().strftime(\'%Y%m%d\')\n
current_today = today\n
transaction_id = None\n
current_id = None\n
if integration_site.getMappingFromCategory(\'causality/%s\' % context.getRelativeUrl()) != \'Causality/%s\' % context.getRelativeUrl():\n
current_id = integration_site.getMappingFromCategory(\'causality/%s\' % context.getRelativeUrl())\n
current_today, transaction_id = current_id.split(\'_\')\n
\n
\n
if transaction_id is not None:\n
context.PaymentTransaction_updateStatus()\n
elif previous_id is not None:\n
context.PaymentTransaction_registerPayzen()\n
\n
if context.getSimulationState() == \'confirmed\':\n
message = context.Base_translateString("Payment was automatically registered to PayZen system.")\n
return context.getWebSiteValue().Base_redirect(keep_items={\'portal_status_message\': message})\n
\n
system_event_kw = {\n
\'portal_type\': \'Payzen Event\',\n
\'source_value\': service,\n
......@@ -62,31 +88,32 @@ system_event_kw = {\n
}\n
system_event = portal.system_event_module.newContent(title=\'User navigation script\', **system_event_kw)\n
\n
today = DateTime().toZone(\'UTC\').asdatetime().strftime(\'%Y%m%d\')\n
transaction_id = str(portal.portal_ids.generateNewId(\n
if today != current_today or integration_site.getMappingFromCategory(\'causality/%s\' % context.getRelativeUrl()) == \'Causality/%s\' % context.getRelativeUrl():\n
# new or too old transaction\n
transaction_id = str(portal.portal_ids.generateNewId(\n
id_group=\'%s_%s\' % (service.getRelativeUrl(), today),\n
id_generator=\'uid\')).zfill(6)\n
\n
mapping_id = \'%s_%s\' % (today, transaction_id)\n
if not integration_site.getMappingFromCategory(\'causality/%s\' % context.getRelativeUrl()) == \'Causality/%s\' % context.getRelativeUrl():\n
system_event.confirm(comment=\'Transaction already mapped in integration tool.\')\n
return \'There was system issue\'\n
try:\n
integration_site.getCategoryFromMapping(\'Causality/%s\' % mapping_id, create_mapping_line=True, create_mapping=True)\n
except ValueError:\n
mapping = integration_site.Causality[mapping_id]\n
mapping.setDestinationReference(\'causality/%s\' % context.getRelativeUrl())\n
else:\n
system_event.confirm(comment=\'Key %s already found!\' % mapping_id)\n
return \'There was system issue\'\n
\n
context.activate().PaymentTransaction_confirm()\n
mapping_id = \'%s_%s\' % (today, transaction_id)\n
try:\n
integration_site.getCategoryFromMapping(\'Causality/%s\' % mapping_id, create_mapping_line=True, create_mapping=True)\n
except ValueError:\n
mapping = integration_site.Causality[mapping_id]\n
mapping.setDestinationReference(\'causality/%s\' % context.getRelativeUrl())\n
if current_today != today:\n
# Cleanup as integration site does not support multiple mappings to with external site\n
integration_site.Causality.deleteContent(current_id.split(\'/\')[1])\n
else:\n
system_event.confirm(comment=\'Key %s already found!\' % mapping_id)\n
return \'There was system issue\'\n
\n
context.setStartDate(now)\n
context.updateCausalityState()\n
payzen_dict = {}\n
payzen_dict.update(\n
vads_currency=integration_site.getMappingFromCategory(\'resource/currency_module/%s\' % context.getResourceReference()).split(\'/\')[-1],\n
vads_amount=str(int(round((context.PaymentTransaction_getTotalPayablePrice() * -100), 0))),\n
vads_trans_date=context.getStartDate().toZone(\'UTC\').asdatetime().strftime(\'%Y%m%d%H%M%S\'),\n
vads_trans_date=now.toZone(\'UTC\').asdatetime().strftime(\'%Y%m%d%H%M%S\'),\n
vads_trans_id=transaction_id,\n
vads_language=\'en\',\n
)\n
......
......@@ -64,6 +64,12 @@
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
......@@ -75,7 +81,7 @@
<item>
<key> <string>href</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
......@@ -139,7 +145,20 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.ERP5Site_getInitialPlannedPaymentTransaction().getRelativeUrl() + \'/AccountingTransaction_startPayment\'</string> </value>
<value> <string>python: here.ERP5Site_getAuthenticatedMemberPersonValue().Person_getOutstandingPayment() is not None</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.ERP5Site_getAuthenticatedMemberPersonValue().Person_getOutstandingPayment().getRelativeUrl() + \'/AccountingTransaction_startPayment\'</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -146,7 +146,9 @@
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>external_validator</string> </key>
......@@ -302,4 +304,21 @@ Registration Payment is begin processed. It will take some time.
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
python: here.ERP5Site_getAuthenticatedMemberPersonValue().Person_countPayment([\'confirmed\']) > 0
]]></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -146,7 +146,9 @@
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>external_validator</string> </key>
......@@ -302,4 +304,21 @@ Registration Payment Information are being updated. Please wait a while.
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string encoding="cdata"><![CDATA[
python: (here.ERP5Site_getAuthenticatedMemberPersonValue().Person_countPayment() == 0 or here.ERP5Site_getAuthenticatedMemberPersonValue().Person_countPayment([\'planned\']) > 0) and here.ERP5Site_getAuthenticatedMemberPersonValue().Person_getOutstandingPayment() is None
]]></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -5,4 +5,5 @@ erp5_jquery
erp5_km
erp5_web
vifib_forge_release
vifib_software_pdm
\ No newline at end of file
vifib_software_pdm
vifib_payzen
\ No newline at end of file
363
\ No newline at end of file
364
\ 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