Commit f090874c authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_*: Don't rely on Related started Payment Transaction

  Drop builder and alarm for update Confirmed Payment transaction
  Update Payment state gadget (JIO)
  Generate the link from the Sale Invoice Transaction rather them Payment (since they might not exist)
  crm: Update from Unpaid Payments to Unpaid Invoices
  Now we rely on lettered/non lettered invoices rather than payments.
parent f38a583a
...@@ -42,19 +42,27 @@ else: ...@@ -42,19 +42,27 @@ else:
elif context.getTotalPrice() == 0: elif context.getTotalPrice() == 0:
result = "Free!" result = "Free!"
else: else:
# Check if there is an ongoing SlapOS payment result = "Pay Now"
payment = context.SaleInvoiceTransaction_getSlapOSPaymentRelatedValue()
if payment is None: # Search to know if there are some payment waiting for confirmation
result = "Unpaid" payment = portal.portal_catalog.getResultValue(
else: portal_type="Payment Transaction",
simulation_state="started",
default_causality_uid=context.getUid(),
default_payment_mode_uid=[portal.portal_categories.payment_mode.payzen.getUid(),
portal.portal_categories.payment_mode.wechat.getUid()],
)
if payment is not None:
# Check if mapping exists # Check if mapping exists
external_payment_id = person.Person_restrictMethodAsShadowUser( if person is not None:
shadow_document=person, external_payment_id = person.Person_restrictMethodAsShadowUser(
callable_object=payment.PaymentTransaction_getExternalPaymentId, shadow_document=person,
argument_list=[])[0] callable_object=payment.PaymentTransaction_getExternalPaymentId,
if external_payment_id is None: argument_list=[])[0]
result = "Pay Now"
else: else:
external_payment_id = payment.PaymentTransaction_getExternalPaymentId()
if external_payment_id is not None:
result = "Waiting for payment confirmation" result = "Waiting for payment confirmation"
return result return result
payment_transaction = context.SaleInvoiceTransaction_getSlapOSPaymentRelatedValue()
if payment_transaction is not None:
return payment_transaction.getRelativeUrl()
<?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>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleInvoiceTransaction_getSlapOSPaymentRelated</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
return portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
simulation_state="started",
default_causality_uid=context.getUid(),
default_payment_mode_uid=[portal.portal_categories.payment_mode.payzen.getUid(),
portal.portal_categories.payment_mode.wechat.getUid()],
)
<?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>**kw</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SaleInvoiceTransaction_getSlapOSPaymentRelatedValue</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -36,7 +36,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin): ...@@ -36,7 +36,7 @@ class TestSlapOSEntityCreatePaymentMixin(SlapOSTestCaseMixin):
def assertPayment(self, payment, invoice): def assertPayment(self, payment, invoice):
self.assertEqual(self.sumReceivable(invoice), payment\ self.assertEqual(self.sumReceivable(invoice), payment\
.PaymentTransaction_getTotalPayablePrice()) .PaymentTransaction_getTotalPayablePrice())
self.assertEqual('confirmed', payment.getSimulationState()) self.assertEqual('started', payment.getSimulationState())
self.assertSameSet([], payment.checkConsistency()) self.assertSameSet([], payment.checkConsistency())
self.assertSameSet([invoice], payment.getCausalityValueList()) self.assertSameSet([invoice], payment.getCausalityValueList())
self.assertSameSet([], payment.getCausalityRelatedValueList( self.assertSameSet([], payment.getCausalityRelatedValueList(
......
# -*- coding: utf-8 -*- # -*- coding:utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# #
############################################################################## ##############################################################################
...@@ -649,8 +663,7 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin): ...@@ -649,8 +663,7 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin):
self.assertEqual(None, to_click_message) self.assertEqual(None, to_click_message)
@changeSkin('RJS') @changeSkin('RJS')
def useWechatManually(self, web_site, user_id, is_email_expected=True): def usePaymentManually(self, web_site, user_id, is_email_expected=True, subscription_request=None):
person = self.portal.portal_catalog.getResultValue( person = self.portal.portal_catalog.getResultValue(
portal_type="Person", portal_type="Person",
user_id=user_id) user_id=user_id)
...@@ -658,37 +671,24 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin): ...@@ -658,37 +671,24 @@ class DefaultScenarioMixin(TestSlapOSSecurityMixin):
self.assertNotEqual(person, None) self.assertNotEqual(person, None)
self.assertInvoiceNotification(person, is_email_expected) self.assertInvoiceNotification(person, is_email_expected)
# If you are using live test, be aware that the call of the alarm can be invoice_list = person.Entity_getOutstandingAmountList()
# not enough for the number of objects on the site. if subscription_request is not None:
document_id = self.portal.portal_catalog.getResultValue( expected_causality = subscription_request.getRelativeUrl()
portal_type="Payment Transaction", filtered_invoice_list = []
simulation_state="started", for invoice in invoice_list:
destination_section_uid=person.getUid() spl = invoice.getCausalityValue()
).getId() if spl is not None and spl.getCausality() == expected_causality:
filtered_invoice_list.append(invoice)
web_site.accounting_module[document_id].\
PaymentTransaction_redirectToManualWechatPayment() self.assertEqual(len(filtered_invoice_list), 1)
invoice_list = filtered_invoice_list
@changeSkin('RJS') else:
def usePayzenManually(self, web_site, user_id, is_email_expected=True): self.assertEqual(len(invoice_list), 1)
person = self.portal.portal_catalog.getResultValue(
portal_type="Person",
user_id=user_id)
self.assertNotEqual(person, None)
self.assertInvoiceNotification(person, is_email_expected)
# Pay to payzen...
# If you are using live test, be aware that the call of the alarm can be
# not enough for the number of objects on the site.
document_id = self.portal.portal_catalog.getResultValue(
portal_type="Payment Transaction",
simulation_state="started",
destination_section_uid=person.getUid()
).getId()
document_id = invoice_list[0].getId()
web_site.accounting_module[document_id].\ web_site.accounting_module[document_id].\
PaymentTransaction_redirectToManualPayzenPayment() SaleInvoiceTransaction_redirectToManualSlapOSPayment()
self.tic()
def assertSubscriptionStopped(self, person): def assertSubscriptionStopped(self, person):
self.login() self.login()
......
...@@ -614,15 +614,6 @@ class SlapOSTestCaseMixin(testSlapOSMixin): ...@@ -614,15 +614,6 @@ class SlapOSTestCaseMixin(testSlapOSMixin):
source="account_module/receivable", source="account_module/receivable",
quantity=-3, quantity=-3,
) )
payment = self.portal.accounting_module.newContent(
portal_type="Payment Transaction",
payment_mode=payment_mode,
causality_value=invoice,
destination_section=destination_section,
created_by_builder=1 # to prevent init script to create lines
)
self.portal.portal_workflow._jumpToStateFor(payment, 'started')
return invoice return invoice
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SlapOSTestCaseMixin</string> </value> <value> <string>SlapOSTestCaseMixin</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <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> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
...@@ -28,12 +28,12 @@ outstanding_amount = person.Entity_statSlapOSOutstandingAmount() ...@@ -28,12 +28,12 @@ outstanding_amount = person.Entity_statSlapOSOutstandingAmount()
# Amount to be ignored, as it comes from the first invoice generated # Amount to be ignored, as it comes from the first invoice generated
# after the subscription. We do not take it into account as no service # after the subscription. We do not take it into account as no service
# was provided yet. # was provided yet.
unpaid_payment_amount = 0 unpaid_invoice_amount = 0
for payment in person.Person_getSubscriptionRequestFirstUnpaidPaymentList(): for invoice in person.Person_getSubscriptionRequestFirstUnpaidInvoiceList():
unpaid_payment_amount += payment.PaymentTransaction_getTotalPayablePrice() unpaid_invoice_amount += invoice.getTotalPrice()
# It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount # It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount
if round(float(outstanding_amount), 2) == round(-float(unpaid_payment_amount), 2): if round(float(outstanding_amount), 2) == round(float(unpaid_invoice_amount), 2):
return ticket, None return ticket, None
if int(outstanding_amount) > 0: if int(outstanding_amount) > 0:
......
...@@ -12,8 +12,8 @@ subscription_request_list = portal.portal_catalog( ...@@ -12,8 +12,8 @@ subscription_request_list = portal.portal_catalog(
creation_date=Query(creation_date=addToDate(DateTime(), to_add={'day': -20}), range="min")) creation_date=Query(creation_date=addToDate(DateTime(), to_add={'day': -20}), range="min"))
for subscription_request in subscription_request_list: for subscription_request in subscription_request_list:
first_period_payment = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady() first_invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
if first_period_payment is not None and first_period_payment.getSimulationState() == "started": if first_invoice is not None and not first_invoice.SaleInvoiceTransaction_isLettered():
unpaid_list.append(first_period_payment) unpaid_list.append(first_invoice)
return unpaid_list return unpaid_list
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Person_getSubscriptionRequestFirstUnpaidPaymentList</string> </value> <value> <string>Person_getSubscriptionRequestFirstUnpaidInvoiceList</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -13,12 +13,12 @@ outstanding_amount = person.Entity_statSlapOSOutstandingAmount() ...@@ -13,12 +13,12 @@ outstanding_amount = person.Entity_statSlapOSOutstandingAmount()
# Amount to be ignored, as it comes from the first invoice generated # Amount to be ignored, as it comes from the first invoice generated
# after the subscription. We do not take it into account as no service # after the subscription. We do not take it into account as no service
# was provided yet. # was provided yet.
unpaid_payment_amount = 0 unpaid_invoice_amount = 0
for payment in person.Person_getSubscriptionRequestFirstUnpaidPaymentList(): for invoice in person.Person_getSubscriptionRequestFirstUnpaidInvoiceList():
unpaid_payment_amount += payment.PaymentTransaction_getTotalPayablePrice() unpaid_invoice_amount += invoice.getTotalPrice()
# It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount # It can't be smaller, we are considernig all open invoices are from unpaid_payment_amount
if round(float(outstanding_amount), 2) == round(-float(unpaid_payment_amount), 2): if round(float(outstanding_amount), 2) == round(float(unpaid_invoice_amount), 2):
context.invalidate(comment="Automatically disabled as balance is %s" % outstanding_amount) context.invalidate(comment="Automatically disabled as balance is %s" % outstanding_amount)
return return
......
...@@ -27,6 +27,52 @@ from DateTime import DateTime ...@@ -27,6 +27,52 @@ from DateTime import DateTime
class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin): class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
def createFinalInvoice(self, person):
template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentSubscriptionInvoiceTemplate())
current_invoice = template.Base_createCloneDocument(batch_mode=1)
current_invoice.edit(
destination_value=person,
destination_section_value=person,
destination_decision_value=person,
start_date=DateTime('2019/10/20'),
stop_date=DateTime('2019/10/20'),
title='Fake Invoice for Demo User Functional',
price_currency="currency_module/EUR",
reference='1')
cell = current_invoice["1"]["movement_0"]
cell.edit(quantity=1)
cell.setPrice(1)
current_invoice.plan()
current_invoice.confirm()
current_invoice.startBuilding()
current_invoice.reindexObject()
current_invoice.stop()
self.tic()
current_invoice.Delivery_manageBuildingCalculatingDelivery()
self.tic()
applied_rule = current_invoice.getCausalityRelated(portal_type="Applied Rule")
for sm in self.portal.portal_catalog(portal_type='Simulation Movement',
simulation_state=['draft', 'planned', None],
left_join_list=['delivery_uid'],
delivery_uid=None,
path="%%%s%%" % applied_rule):
if sm.getDelivery() is not None:
continue
root_applied_rule = sm.getRootAppliedRule()
root_applied_rule_path = root_applied_rule.getPath()
sm.getCausalityValue(portal_type='Business Link').build(
path='%s/%%' % root_applied_rule_path)
return current_invoice
def test_alarm_expected_person(self): def test_alarm_expected_person(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
...@@ -35,14 +81,7 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin): ...@@ -35,14 +81,7 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
) )
person.validate() person.validate()
payment = self.portal.accounting_module.newContent( self.createFinalInvoice(person)
portal_type='Payment Transaction',
title="Payment Transaction for TestSlapOSCRMCreateRegularisationRequest person %s" % new_id,
destination_section=person.getRelativeUrl(),
start_date=DateTime()
)
payment.confirm()
payment.start()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
...@@ -56,17 +95,9 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin): ...@@ -56,17 +95,9 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
self.createFinalInvoice(person)
person.invalidate() person.invalidate()
payment = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Payment Transaction for TestSlapOSCRMCreateRegularisationRequest person %s" % new_id,
destination_section=person.getRelativeUrl(),
start_date=DateTime()
)
payment.confirm()
payment.start()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request slapos_crm_create_regularisation_request
...@@ -79,23 +110,31 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin): ...@@ -79,23 +110,31 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
title="Test person %s" % new_id title="Test person %s" % new_id
) )
person.validate() person.validate()
current_invoice = self.createFinalInvoice(person)
payment_template = self.portal.restrictedTraverse(
self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
payment = payment_template.Base_createCloneDocument(batch_mode=1)
for line in payment.contentValues():
if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1)
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
payment = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Payment Transaction for TestSlapOSCRMCreateRegularisationRequest person %s" % new_id,
destination_section=person.getRelativeUrl(),
start_date=DateTime()
)
payment.confirm() payment.confirm()
payment.start() payment.start()
payment.setCausalityValue(current_invoice)
payment.setDestinationSectionValue(person)
payment.stop() payment.stop()
self.tic()
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request slapos_crm_create_regularisation_request
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest") self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest")
def test_alarm_payment_confirmed(self): def test_alarm_payment_started(self):
new_id = self.generateNewId() new_id = self.generateNewId()
person = self.portal.person_module.newContent( person = self.portal.person_module.newContent(
portal_type='Person', portal_type='Person',
...@@ -103,18 +142,26 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin): ...@@ -103,18 +142,26 @@ class TestSlapOSCRMCreateRegularisationRequest(SlapOSTestCaseMixin):
) )
person.validate() person.validate()
payment = self.portal.accounting_module.newContent( current_invoice = self.createFinalInvoice(person)
portal_type='Payment Transaction', payment_template = self.portal.restrictedTraverse(
title="Payment Transaction for TestSlapOSCRMCreateRegularisationRequest person %s" % new_id, self.portal.portal_preferences.getPreferredDefaultPrePaymentTemplate())
destination_section=person.getRelativeUrl(), payment = payment_template.Base_createCloneDocument(batch_mode=1)
start_date=DateTime()
) for line in payment.contentValues():
if line.getSource() == "account_module/payment_to_encash":
line.setQuantity(-1)
elif line.getSource() == "account_module/receivable":
line.setQuantity(1)
payment.confirm() payment.confirm()
payment.start()
payment.setCausalityValue(current_invoice)
payment.setDestinationSectionValue(person)
self.tic() self.tic()
alarm = self.portal.portal_alarms.\ alarm = self.portal.portal_alarms.\
slapos_crm_create_regularisation_request slapos_crm_create_regularisation_request
self._test_alarm_not_visited(alarm, person, "Person_checkToCreateRegularisationRequest") self._test_alarm(alarm, person, "Person_checkToCreateRegularisationRequest")
class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinWithAbort): class TestSlapOSCrmInvalidateSuspendedRegularisationRequest(SlapOSTestCaseMixinWithAbort):
......
...@@ -149,7 +149,7 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template): ...@@ -149,7 +149,7 @@ def makeTestSlapOSCodingStyleTestCase(tested_business_template):
'slapos_crm_monitoring/Event_checkCustomerAsSourceOrDestinationConsistency', 'slapos_crm_monitoring/Event_checkCustomerAsSourceOrDestinationConsistency',
'slapos_crm_monitoring/SupportRequest_checkCausalitySourceDestinationConsistency', 'slapos_crm_monitoring/SupportRequest_checkCausalitySourceDestinationConsistency',
'slapos_crm_monitoring/SupportRequest_getLastEvent', 'slapos_crm_monitoring/SupportRequest_getLastEvent',
'slapos_crm/Person_getSubscriptionRequestFirstUnpaidPaymentList', 'slapos_crm/Person_getSubscriptionRequestFirstUnpaidInvoiceList',
'slapos_crm/RegularisationRequest_afterClone', 'slapos_crm/RegularisationRequest_afterClone',
'slapos_crm/RegularisationRequest_getResourceItemList', 'slapos_crm/RegularisationRequest_getResourceItemList',
'slapos_crm/RegularisationRequest_init', 'slapos_crm/RegularisationRequest_init',
......
# -*- coding: utf-8 -*- # -*- coding:utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# #
############################################################################## ##############################################################################
...@@ -249,10 +263,10 @@ class TestSlapOSDefaultScenario(DefaultScenarioMixin): ...@@ -249,10 +263,10 @@ class TestSlapOSDefaultScenario(DefaultScenarioMixin):
self.assertPersonDocumentCoverage(person) self.assertPersonDocumentCoverage(person)
self.login(public_person.getUserId()) self.login(public_person.getUserId())
self.usePayzenManually(self.web_site, public_person.getUserId()) self.usePaymentManually(self.web_site, public_person.getUserId())
self.login(friend_person.getUserId()) self.login(friend_person.getUserId())
self.usePayzenManually(self.web_site, friend_person.getUserId()) self.usePaymentManually(self.web_site, friend_person.getUserId())
class TestSlapOSDefaultCRMEscalation(DefaultScenarioMixin): class TestSlapOSDefaultCRMEscalation(DefaultScenarioMixin):
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
} }
if (1 || (result.data.rows[i].hasOwnProperty("id"))) { if (1 || (result.data.rows[i].hasOwnProperty("id"))) {
value = result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas; value = result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas;
value.jio_key = result.data.rows[i].id;
result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas = { result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas = {
field_gadget_param : { field_gadget_param : {
css_class: "", css_class: "",
......
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1667590788.38</float> <float>1671074456.17</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
} }
if (1 || (result.data.rows[i].hasOwnProperty("id"))) { if (1 || (result.data.rows[i].hasOwnProperty("id"))) {
value = result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas; value = result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas;
value.jio_key = result.data.rows[i].id;
result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas = { result.data.rows[i].value.AccountingTransaction_getPaymentStateAsHateoas = {
field_gadget_param : { field_gadget_param : {
css_class: "", css_class: "",
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1004.6631.33059.11776</string> </value> <value> <string>1004.12379.1853.8140</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1667930581.61</float> <float>1671070228.44</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -160,7 +160,7 @@ ...@@ -160,7 +160,7 @@
"title": result[1][5], "title": result[1][5],
"default": { "default": {
state: gadget.state.doc.payment_state, state: gadget.state.doc.payment_state,
payment_transaction: gadget.state.doc.payment_transaction jio_key: gadget.state.jio_key
}, },
"css_class": "", "css_class": "",
"required": 1, "required": 1,
......
...@@ -236,7 +236,7 @@ ...@@ -236,7 +236,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>999.2068.62564.17</string> </value> <value> <string>1004.12196.28653.10734</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1667919626.06</float> <float>1671070129.29</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -14,16 +14,15 @@ ...@@ -14,16 +14,15 @@
link; link;
return gadget.getTranslationDict(['Pay Now']) return gadget.getTranslationDict(['Pay Now'])
.push(function (translation_dict) { .push(function (translation_dict) {
if ((gadget.state.payment_transaction !== null) && if (gadget.state.payment_state === 'Pay Now') {
(gadget.state.payment_transaction !== undefined)) {
link = domsugar("li", {}, link = domsugar("li", {},
[ [
domsugar("a", { domsugar("a", {
class: "ui-btn ui-first-child ui-btn-icon-center", class: "ui-btn ui-first-child ui-btn-icon-center",
text: translation_dict["Pay Now"], text: translation_dict["Pay Now"],
href: gadget.state.hateoas_url + href: gadget.state.hateoas_url +
gadget.state.payment_transaction + gadget.state.jio_key +
"/PaymentTransaction_redirectToManualSlapOSPayment" "/SaleInvoiceTransaction_redirectToManualSlapOSPayment"
}) })
]); ]);
} else { } else {
...@@ -41,7 +40,7 @@ ...@@ -41,7 +40,7 @@
return gadget.getSetting("hateoas_url") return gadget.getSetting("hateoas_url")
.push(function (hateoas_url) { .push(function (hateoas_url) {
return gadget.changeState({ return gadget.changeState({
payment_transaction: options.value.payment_transaction, jio_key: options.value.jio_key,
payment_state: options.value.state, payment_state: options.value.state,
hateoas_url: hateoas_url hateoas_url: hateoas_url
}); });
......
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1667929052.34</float> <float>1671070046.11</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
state = context.AccountingTransaction_getPaymentState() state = context.AccountingTransaction_getPaymentState()
payment_transaction = None
payment_mode = None payment_mode = None
if state == "Pay Now": if state == "Pay Now":
payment_transaction_value = context.SaleInvoiceTransaction_getSlapOSPaymentRelatedValue() payment_mode = context.getPaymentMode() # ???
payment_transaction = payment_transaction_value.getRelativeUrl()
payment_mode = payment_transaction_value.getPaymentMode()
return {"state": context.Base_translateString(state), return {"state": context.Base_translateString(state),
"payment_mode": payment_mode, "payment_mode": payment_mode}
"payment_transaction": payment_transaction}
...@@ -100,7 +100,6 @@ ...@@ -100,7 +100,6 @@
<string>my_resource_title</string> <string>my_resource_title</string>
<string>my_payment_transaction_external_id</string> <string>my_payment_transaction_external_id</string>
<string>my_payment_state</string> <string>my_payment_state</string>
<string>my_payment_transaction</string>
</list> </list>
</value> </value>
</item> </item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>default</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_payment_transaction</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_string_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payment Transaction</string> </value>
</item>
</dictionary>
</value>
</item>
</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>python: context.SaleInvoiceTransaction_getSlapOSPaymentRelated()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -76,12 +76,12 @@ ...@@ -76,12 +76,12 @@
</tr> </tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
...@@ -165,12 +165,12 @@ ...@@ -165,12 +165,12 @@
</tr> </tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
...@@ -284,12 +284,12 @@ ...@@ -284,12 +284,12 @@
</tr> </tr>
<tr> <tr>
<td>waitForElementPresent</td> <td>waitForElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'PaymentTransaction_redirectToManualSlapOSPayment')]</td> <td> //div[contains(@data-gadget-url, 'gadget_slapos_invoice_state.html')]//a[contains(@href, 'SaleInvoiceTransaction_redirectToManualSlapOSPayment')]</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
......
<?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>slapos_payzen_update_confirmed_payment</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>Handles confirmed Payment Transactions with PayZen interface</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Order Builder" 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>categories</string> </key>
<value>
<tuple>
<string>destination/organisation_module/slapos</string>
<string>destination_section/organisation_module/slapos</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>delivery_after_generation_script_id</string> </key>
<value> <string>PaymentTransaction_postOrderBuild</string> </value>
</item>
<item>
<key> <string>delivery_cell_portal_type</string> </key>
<value> <string>Delivery Cell</string> </value>
</item>
<item>
<key> <string>delivery_cell_separate_order</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>delivery_line_portal_type</string> </key>
<value> <string>Accounting Transaction Line</string> </value>
</item>
<item>
<key> <string>delivery_module</string> </key>
<value> <string>accounting_module</string> </value>
</item>
<item>
<key> <string>delivery_portal_type</string> </key>
<value> <string>Payment Transaction</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>slapos_payment_transaction_builder</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Order Builder</string> </value>
</item>
<item>
<key> <string>simulation_select_method_id</string> </key>
<value> <string>OrderBuilder_generateUnrelatedInvoiceList</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Payment Builder</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 Movement Group" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>collect_order_group/delivery</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>category_movement_group_on_delivery</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Movement Group</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value>
<tuple>
<string>causality</string>
<string>destination_payment</string>
<string>destination_section</string>
<string>price_currency</string>
<string>resource</string>
<string>source_payment</string>
<string>source_section</string>
<string>specialise</string>
<string>payment_mode</string>
</tuple>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>update_always</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Category Movement Group" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>collect_order_group/line</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>category_movement_group_on_line</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Category Movement Group</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value>
<tuple>
<string>destination</string>
<string>source</string>
</tuple>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>update_always</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Property Movement Group" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>collect_order_group/line</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>property_movement_group_on_line</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Property Movement Group</string> </value>
</item>
<item>
<key> <string>tested_property</string> </key>
<value>
<tuple>
<string>start_date</string>
<string>stop_date</string>
</tuple>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>property_movement_group_on_line</string> </value>
</item>
<item>
<key> <string>update_always</string> </key>
<value> <int>0</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Payment Transaction",
simulation_state=["confirmed"],
causality_state=["draft"],
payment_mode_uid=portal.portal_categories.payment_mode.payzen.getUid(),
method_id='PaymentTransaction_startPayzenPayment',
packet_size=1, # just one to minimise errors
activate_kw={'tag': tag}
)
context.activate(after_tag=tag).getId()
<?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>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_updatePayzenConfirmedPaymentTransaction</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
newTempSimulationMovement = portal.portal_trash.newContent
select_dict = {
'causality_payment_transaction_related_uid': None,
'causality_subscription_request_related_uid': None,
}
select_kw = kwargs.copy()
select_kw.pop('portal_type', None)
select_kw.pop('delivery_relative_url_list', None)
select_kw.update(
portal_type='Sale Invoice Transaction',
simulation_state='stopped',
default_payment_mode_uid=(portal.portal_categories.payment_mode.payzen.getUid(),
portal.portal_categories.payment_mode.wechat.getUid()),
limit=10, # do only some in one shot
select_dict=select_dict,
left_join_list=select_dict.keys(),
causality_payment_transaction_related_uid=None,
causality_subscription_request_related_uid=None
)
default_source_uid=portal.restrictedTraverse('account_module/receivable').getUid()
movement_list = []
_id = 1
for invoice in portal.portal_catalog(**select_kw):
invoice.getObject().serialize() # in order to avoid selection on concurrent transactions
payment_tag = "sale_invoice_transaction_order_builder_%s" % invoice.getObject().getUid()
if context.REQUEST.get(payment_tag, None) is not None or \
context.portal_activities.countMessageWithTag(payment_tag) > 0:
# Invoice was selected before the payment be indexed or it was already created on this transaction
# so skip the invoice for now.
continue
quantity = 0.
for movement in invoice.searchFolder(portal_type='Sale Invoice Transaction Line',
default_source_uid=default_source_uid):
quantity += movement.getQuantity()
temp_movement_kw = dict(
portal_type="Simulation Movement",
causality=invoice.getRelativeUrl(),
source_section=invoice.getSourceSection(),
destination_section=invoice.getDestinationSection(),
resource=invoice.getResource(),
price_currency=invoice.getResource(),
start_date=invoice.getStartDate(),
stop_date=invoice.getStopDate(),
specialise=invoice.getSpecialise(),
payment_mode=invoice.getPaymentMode(),
source_payment='%s/bank_account' % invoice.getSourceSection(), # the other place defnied: business process
)
temp_movement_rec = newTempSimulationMovement(
temp_object=True, id=str(_id),
quantity=-1 * quantity,
source='account_module/receivable',
destination='account_module/payable',
**temp_movement_kw
)
_id += 1
temp_movement_bank = newTempSimulationMovement(
temp_object=True, id=str(_id),
quantity=1 * quantity,
source='account_module/payment_to_encash',
destination='account_module/payment_to_encash',
**temp_movement_kw
)
_id += 1
movement_list.extend([temp_movement_rec, temp_movement_bank])
return movement_list
<?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, **kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>OrderBuilder_generateUnrelatedInvoiceList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from DateTime import DateTime
state = context.getSimulationState()
transaction_amount = int(round((context.PaymentTransaction_getTotalPayablePrice() * -100), 2))
if (state != 'confirmed') or (context.getPaymentMode() != 'payzen') or (transaction_amount == 0):
if (transaction_amount == 0):
invoice = context.getCausalityValue(portal_types="Sale Invoice Transaction")
if invoice is not None and round(invoice.getTotalPrice(), 2) == 0:
context.edit(payment_mode="wire_transfer")
return
else:
# Request manual payment
context.start(comment='Requested manual payment')
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaymentTransaction_startPayzenPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved. # -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
from DateTime import DateTime from DateTime import DateTime
class TestSlapOSPayzenUpdateConfirmedPayment(SlapOSTestCaseMixinWithAbort):
def _simulatePaymentTransaction_startPayzenPayment(self):
script_name = 'PaymentTransaction_startPayzenPayment'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PaymentTransaction_startPayzenPayment') """ )
self.commit()
def _dropPaymentTransaction_startPayzenPayment(self):
script_name = 'PaymentTransaction_startPayzenPayment'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
self.commit()
def test_alarm_confirmed_draft_payzen(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.tic()
self._simulatePaymentTransaction_startPayzenPayment()
try:
self.portal.portal_alarms.slapos_payzen_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startPayzenPayment()
self.tic()
self.assertEqual(
'Visited by PaymentTransaction_startPayzenPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_confirmed(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
self.tic()
self._simulatePaymentTransaction_startPayzenPayment()
try:
self.portal.portal_alarms.slapos_payzen_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startPayzenPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startPayzenPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_draft(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.portal.portal_workflow._jumpToStateFor(transaction, 'solved')
self.tic()
self._simulatePaymentTransaction_startPayzenPayment()
try:
self.portal.portal_alarms.slapos_payzen_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startPayzenPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startPayzenPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_payzen(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.tic()
self._simulatePaymentTransaction_startPayzenPayment()
try:
self.portal.portal_alarms.slapos_payzen_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startPayzenPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startPayzenPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def _simulatePaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""return 1""")
self.commit()
def _simulatePaymentTransaction_getZeroTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""return 0""")
self.commit()
def _dropPaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
self.commit()
def test_not_confirmed_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startPayzenPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_not_payzen_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startPayzenPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_zero_amount_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getZeroTotalPayablePrice()
try:
transaction.PaymentTransaction_startPayzenPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_expected_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="payzen",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startPayzenPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), 'started')
class TestSlapOSPayzenUpdateStartedPayment(SlapOSTestCaseMixinWithAbort): class TestSlapOSPayzenUpdateStartedPayment(SlapOSTestCaseMixinWithAbort):
def test_not_started_payment(self): def test_not_started_payment(self):
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testSlapOSPayzenAlarm</string> </value> <value> <string>testSlapOSPayzenAlarm</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <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> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved. # -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
from DateTime import DateTime from DateTime import DateTime
...@@ -831,25 +851,6 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -831,25 +851,6 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
self.assertEqual("%s/already_registered" % payment.getRelativeUrl(), self.assertEqual("%s/already_registered" % payment.getRelativeUrl(),
redirect) redirect)
class TestSlapOSPayzenSaleInvoiceTransaction_getSlapOSPaymentRelatedValue(
SlapOSTestCaseMixinWithAbort):
def test_SaleInvoiceTransaction_getSlapOSPaymentRelatedValue(self):
invoice = self.createPayzenSaleInvoiceTransaction()
self.tic()
payment = invoice.SaleInvoiceTransaction_getSlapOSPaymentRelatedValue()
self.assertNotEqual(None, payment)
self.assertEqual(payment.getSimulationState(), "started")
self.assertEqual(payment.getCausalityValue(), invoice)
self.assertEqual(payment.getPaymentModeUid(),
self.portal.portal_categories.payment_mode.payzen.getUid())
payment.setStartDate(DateTime())
payment.stop()
payment.immediateReindexObject()
payment = invoice.SaleInvoiceTransaction_getSlapOSPaymentRelatedValue()
self.assertEqual(None, payment)
class TestSlapOSPayzenSaleInvoiceTransaction_createReversalPayzenTransaction( class TestSlapOSPayzenSaleInvoiceTransaction_createReversalPayzenTransaction(
SlapOSTestCaseMixinWithAbort): SlapOSTestCaseMixinWithAbort):
......
accounting_module/template_sale_invoice_transaction accounting_module/template_sale_invoice_transaction
accounting_module/template_sale_invoice_transaction/** accounting_module/template_sale_invoice_transaction/**
portal_alarms/slapos_payzen_update_confirmed_payment
portal_alarms/slapos_payzen_update_started_payment portal_alarms/slapos_payzen_update_started_payment
portal_integrations/slapos_payzen_test_integration portal_integrations/slapos_payzen_test_integration
portal_integrations/slapos_payzen_test_integration/Causality portal_integrations/slapos_payzen_test_integration/Causality
portal_integrations/slapos_payzen_test_integration/Resource portal_integrations/slapos_payzen_test_integration/Resource
portal_integrations/slapos_payzen_test_integration/Resource/** portal_integrations/slapos_payzen_test_integration/Resource/**
portal_integrations/slapos_payzen_test_integration/SourceProject portal_integrations/slapos_payzen_test_integration/SourceProject
portal_orders/slapos_payment_transaction_builder
portal_orders/slapos_payment_transaction_builder/**
portal_secure_payments/slapos_payzen_test portal_secure_payments/slapos_payzen_test
portal_secure_payments/slapos_payzen_test/** portal_secure_payments/slapos_payzen_test/**
sale_trade_condition_module/payzen_sale_trade_condition sale_trade_condition_module/payzen_sale_trade_condition
......
...@@ -25,7 +25,7 @@ notification_mapping_dict = { ...@@ -25,7 +25,7 @@ notification_mapping_dict = {
'name': recipient.getTitle(), 'name': recipient.getTitle(),
'subscription_title': context.getTitle(), 'subscription_title': context.getTitle(),
# Possible more actions goes here # Possible more actions goes here
'payment_relative_relative_url': payment.getRelativeUrl()} 'payment_relative_relative_url': invoice.getRelativeUrl()}
# Preserve HTML else convert to text # Preserve HTML else convert to text
if notification_message.getContentType() == "text/html": if notification_message.getContentType() == "text/html":
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>payment</string> </value> <value> <string>invoice</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -32,19 +32,17 @@ if instance_tree is not None: ...@@ -32,19 +32,17 @@ if instance_tree is not None:
context.start(comment=comment) context.start(comment=comment)
context.stop(comment=comment) context.stop(comment=comment)
first_period_payment = context.SubscriptionRequest_verifyPaymentBalanceIsReady() invoice = context.SubscriptionRequest_verifyPaymentBalanceIsReady()
if not first_period_payment: if not invoice:
# Payment isn't available for the user # Invoice isn't available for the user to Pay
return "Skipped (Payment isn't ready)" return "Skipped (Payment isn't ready)"
if not context.SubscriptionRequest_verifyInstanceIsAllocated(): if not context.SubscriptionRequest_verifyInstanceIsAllocated():
# Only continue if instance is ready # Only continue if instance is ready
return "Skipped (Instance isn't ready)" return "Skipped (Instance isn't ready)"
invoice = first_period_payment.getCausalityValue()
# Link to be sent is the invoice one # Link to be sent is the invoice one
if context.SubscriptionRequest_notifyPaymentIsReady(payment=invoice): if context.SubscriptionRequest_notifyPaymentIsReady(invoice):
context.confirm(comment="Payment is ready for the user") context.confirm(comment="Payment is ready for the user")
return "Payment is ready for the user" return "Payment is ready for the user"
......
portal = context.getPortalObject() portal = context.getPortalObject()
payment = context.SubscriptionRequest_verifyPaymentBalanceIsReady() invoice = context.SubscriptionRequest_verifyPaymentBalanceIsReady()
if payment is not None: if invoice is not None:
if payment.getSimulationState() in ['stopped', 'delivered']: if invoice.SaleInvoiceTransaction_isLettered():
# Payment Transaction is payed # Invoice is payed
return True return True
person = context.getDestinationSectionValue() person = context.getDestinationSectionValue()
...@@ -18,5 +18,5 @@ if payment is not None: ...@@ -18,5 +18,5 @@ if payment is not None:
not (person.Entity_statSlapOSOutstandingAmount() > 0)): not (person.Entity_statSlapOSOutstandingAmount() > 0)):
return True return True
# Payment Transaction isn't payed # Invoice isn't payed
return False return False
...@@ -25,12 +25,10 @@ for packing_list in portal.portal_catalog( ...@@ -25,12 +25,10 @@ for packing_list in portal.portal_catalog(
): ):
for invoice in packing_list.getCausalityRelatedValueList( for invoice in packing_list.getCausalityRelatedValueList(
portal_type="Sale Invoice Transaction"): portal_type="Sale Invoice Transaction"):
for payment in invoice.getCausalityRelatedValueList(
portal_type=["Payment Transaction", "Sale Invoice Transaction"]): # XXX How to check if the invoice is ready to be payed
if payment.getSimulationState() in ["stopped", "delivered", "started"]: if invoice.getSimulationState() in ['stopped', 'delivered'] and \
# Invoice is already paied so we just move foward not invoice.checkConsistency():
if not payment.checkConsistency(): return invoice
return payment
# Payment isn't ready # Invoice inst ready to be payed
return
...@@ -338,9 +338,9 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -338,9 +338,9 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
notification_message="subscription_request-payment-is-ready"): notification_message="subscription_request-payment-is-ready"):
self.checkSubscriptionRequest(subscription_request, email, self.checkSubscriptionRequest(subscription_request, email,
subscription_condition) subscription_condition)
payment = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady() invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
self.assertNotEqual(payment, None) self.assertNotEqual(invoice, None)
self.assertEqual(payment.getSimulationState(), 'started') self.assertEqual(invoice.getSimulationState(), 'stopped')
# Assert instance is allocated and without error # Assert instance is allocated and without error
self.assertEqual(True, self.assertEqual(True,
...@@ -375,13 +375,9 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -375,13 +375,9 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
person = subscription_request.getDestinationSectionValue() person = subscription_request.getDestinationSectionValue()
self.login(person.getUserId()) self.login(person.getUserId())
payment = self.portal.portal_catalog.getResultValue( invoice_list = person.Entity_getOutstandingAmountList()
portal_type="Payment Transaction", self.assertEqual(len(invoice_list), 1)
simulation_state="started") sale_transaction_invoice = invoice_list[0].getObject()
sale_transaction_invoice = payment.getCausalityValue(
portal_type="Sale Invoice Transaction"
)
self.logout() self.logout()
self.login() self.login()
...@@ -447,8 +443,11 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -447,8 +443,11 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
quantity = subscription_request.getQuantity() quantity = subscription_request.getQuantity()
self.login(person.getUserId()) self.login(person.getUserId())
self.usePayzenManually(self.web_site, person.getUserId(), is_email_expected=False) self.usePaymentManually(
self.web_site,
person.getUserId(),
is_email_expected=False,
subscription_request=subscription_request)
self.logout() self.logout()
self.login() self.login()
...@@ -485,7 +484,10 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -485,7 +484,10 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
quantity = subscription_request.getQuantity() quantity = subscription_request.getQuantity()
self.login(person.getUserId()) self.login(person.getUserId())
self.usePayzenManually(self.web_site, person.getUserId()) self.usePaymentManually(
self.web_site,
person.getUserId(),
subscription_request=subscription_request)
self.logout() self.logout()
self.login() self.login()
...@@ -524,7 +526,11 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -524,7 +526,11 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST") self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST")
self.login(person.getUserId()) self.login(person.getUserId())
self.useWechatManually(self.web_site, person.getUserId(), is_email_expected=False) self.usePaymentManually(
self.web_site,
person.getUserId(),
is_email_expected=False,
subscription_request=subscription_request)
self.logout() self.logout()
self.login() self.login()
...@@ -556,7 +562,10 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -556,7 +562,10 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST") self.portal.portal_secure_payments.slapos_wechat_test.setWechatMode("UNITTEST")
self.login(person.getUserId()) self.login(person.getUserId())
self.useWechatManually(self.web_site, person.getUserId()) self.usePaymentManually(
self.web_site,
person.getUserId(),
subscription_request=subscription_request)
self.logout() self.logout()
self.login() self.login()
...@@ -972,9 +981,8 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans ...@@ -972,9 +981,8 @@ return dict(vads_url_already_registered="%s/already_registered" % (payment_trans
"TestSubscriptionSkins Notification Message %s %s" % ( "TestSubscriptionSkins Notification Message %s %s" % (
subscription_request.getLanguage(), notification_message), subscription_request.getLanguage(), notification_message),
mail_message.getTitle()) mail_message.getTitle())
payment = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady() invoice = subscription_request.SubscriptionRequest_verifyPaymentBalanceIsReady()
self.assertEqual(payment.getSimulationState(), 'started') self.assertEqual(invoice.getSimulationState(), 'stopped')
invoice = payment.getCausalityValue()
self.assertTrue(invoice.getRelativeUrl() in \ self.assertTrue(invoice.getRelativeUrl() in \
mail_message.getTextContent()) mail_message.getTextContent())
self.assertTrue(subscription_request.getDestinationSectionTitle() in \ self.assertTrue(subscription_request.getDestinationSectionTitle() in \
......
<?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_updateWechatConfirmedPaymentTransaction</string> </value>
</item>
<item>
<key> <string>automatic_solve</string> </key>
<value> <int>0</int> </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>slapos_wechat_update_confirmed_payment</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>Handles confirmed Payment Transactions with Wechat interface</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
portal = context.getPortalObject()
portal.portal_catalog.searchAndActivate(
portal_type="Payment Transaction",
simulation_state=["confirmed"],
causality_state=["draft"],
payment_mode_uid=portal.portal_categories.payment_mode.wechat.getUid(),
method_id='PaymentTransaction_startWechatPayment',
packet_size=1, # just one to minimise errors
activate_kw={'tag': tag}
)
context.activate(after_tag=tag).getId()
<?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>tag, fixit, params</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Alarm_updateWechatConfirmedPaymentTransaction</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
from DateTime import DateTime
state = context.getSimulationState()
transaction_amount = int(round((context.PaymentTransaction_getTotalPayablePrice() * -100), 2))
if (state != 'confirmed') or (context.getPaymentMode() != 'wechat') or (transaction_amount == 0):
if (transaction_amount == 0):
invoice = context.getCausalityValue(portal_types="Sale Invoice Transaction")
if invoice is not None and round(invoice.getTotalPrice(), 2) == 0:
context.edit(payment_mode="wire_transfer")
return
else:
# Request manual payment
context.start(comment='Requested manual payment')
<?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></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>PaymentTransaction_startWechatPayment</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
# Copyright (c) 2002-2012 Nexedi SA and Contributors. All Rights Reserved. # -*- coding:utf-8 -*-
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort from erp5.component.test.SlapOSTestCaseMixin import SlapOSTestCaseMixinWithAbort
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
from DateTime import DateTime from DateTime import DateTime
class TestSlapOSWechatUpdateConfirmedPayment(SlapOSTestCaseMixinWithAbort):
def _simulatePaymentTransaction_startWechatPayment(self):
script_name = 'PaymentTransaction_startWechatPayment'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""portal_workflow = context.portal_workflow
portal_workflow.doActionFor(context, action='edit_action', comment='Visited by PaymentTransaction_startWechatPayment') """ )
self.commit()
def _dropPaymentTransaction_startWechatPayment(self):
script_name = 'PaymentTransaction_startWechatPayment'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
self.commit()
def test_alarm_confirmed_draft_wechat(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.tic()
self._simulatePaymentTransaction_startWechatPayment()
try:
self.portal.portal_alarms.slapos_wechat_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startWechatPayment()
self.tic()
self.assertEqual(
'Visited by PaymentTransaction_startWechatPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_confirmed(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
self.tic()
self._simulatePaymentTransaction_startWechatPayment()
try:
self.portal.portal_alarms.slapos_wechat_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startWechatPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startWechatPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_draft(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.portal.portal_workflow._jumpToStateFor(transaction, 'solved')
self.tic()
self._simulatePaymentTransaction_startWechatPayment()
try:
self.portal.portal_alarms.slapos_wechat_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startWechatPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startWechatPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def test_alarm_not_wechat(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self.tic()
self._simulatePaymentTransaction_startWechatPayment()
try:
self.portal.portal_alarms.slapos_wechat_update_confirmed_payment.activeSense()
self.tic()
finally:
self._dropPaymentTransaction_startWechatPayment()
self.tic()
self.assertNotEqual(
'Visited by PaymentTransaction_startWechatPayment',
transaction.workflow_history['edit_workflow'][-1]['comment'])
def _simulatePaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""return 1""")
self.commit()
def _simulatePaymentTransaction_getZeroTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
raise ValueError('Precondition failed: %s exists in custom' % script_name)
createZODBPythonScript(self.portal.portal_skins.custom,
script_name,
'*args, **kwargs',
'# Script body\n'
"""return 0""")
self.commit()
def _dropPaymentTransaction_getTotalPayablePrice(self):
script_name = 'PaymentTransaction_getTotalPayablePrice'
if script_name in self.portal.portal_skins.custom.objectIds():
self.portal.portal_skins.custom.manage_delObjects(script_name)
self.commit()
def test_not_confirmed_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startWechatPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_not_wechat_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startWechatPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_zero_amount_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
simulation_state = transaction.getSimulationState()
modification_date = transaction.getModificationDate()
self._simulatePaymentTransaction_getZeroTotalPayablePrice()
try:
transaction.PaymentTransaction_startWechatPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), simulation_state)
self.assertEqual(transaction.getModificationDate(), modification_date)
def test_expected_payment(self):
new_id = self.generateNewId()
transaction = self.portal.accounting_module.newContent(
portal_type='Payment Transaction',
title="Transaction %s" % new_id,
reference="TESTTRANS-%s" % new_id,
payment_mode="wechat",
)
self.portal.portal_workflow._jumpToStateFor(transaction, 'confirmed')
self._simulatePaymentTransaction_getTotalPayablePrice()
try:
transaction.PaymentTransaction_startWechatPayment()
finally:
self._dropPaymentTransaction_getTotalPayablePrice()
self.assertEqual(transaction.getSimulationState(), 'started')
class TestSlapOSWechatUpdateStartedPayment(SlapOSTestCaseMixinWithAbort): class TestSlapOSWechatUpdateStartedPayment(SlapOSTestCaseMixinWithAbort):
def test_not_started_payment(self): def test_not_started_payment(self):
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>testSlapOSWechatAlarm</string> </value> <value> <string>testSlapOSWechatAlarm</string> </value>
...@@ -55,28 +49,13 @@ ...@@ -55,28 +49,13 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <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> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -89,7 +68,7 @@ ...@@ -89,7 +68,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -98,7 +77,7 @@ ...@@ -98,7 +77,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="4" aka="AAAAAAAAAAQ="> <record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
image_module/wechat** image_module/wechat**
portal_alarms/slapos_wechat_update_confirmed_payment
portal_alarms/slapos_wechat_update_started_payment portal_alarms/slapos_wechat_update_started_payment
portal_integrations/slapos_wechat_test_integration portal_integrations/slapos_wechat_test_integration
portal_integrations/slapos_wechat_test_integration/Causality portal_integrations/slapos_wechat_test_integration/Causality
......
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