MambuPy 2.0.0b45__tar.gz → 2.0.0b47__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/__init__.py +1 -1
  2. {MambuPy-2.0.0b45/mambupy → MambuPy-2.0.0b47/MambuPy}/api/connector/rest.py +1 -1
  3. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/entities.py +17 -5
  4. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambuloan.py +28 -11
  5. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambuproduct.py +4 -2
  6. {MambuPy-2.0.0b45/mambupy → MambuPy-2.0.0b47/MambuPy}/api/mambustruct.py +5 -2
  7. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambutransaction.py +3 -1
  8. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambuuser.py +2 -0
  9. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/mambuutil.py +10 -3
  10. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_centres.py +1 -0
  11. {MambuPy-2.0.0b45/mambupy → MambuPy-2.0.0b47/MambuPy}/orm/schema_loans.py +3 -1
  12. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy.egg-info/PKG-INFO +1 -1
  13. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/PKG-INFO +1 -1
  14. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/__init__.py +1 -1
  15. {MambuPy-2.0.0b45/MambuPy → MambuPy-2.0.0b47/mambupy}/api/connector/rest.py +1 -1
  16. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/entities.py +17 -5
  17. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambuloan.py +28 -11
  18. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambuproduct.py +4 -2
  19. {MambuPy-2.0.0b45/MambuPy → MambuPy-2.0.0b47/mambupy}/api/mambustruct.py +5 -2
  20. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambutransaction.py +3 -1
  21. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambuuser.py +2 -0
  22. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/mambuutil.py +10 -3
  23. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_centres.py +1 -0
  24. {MambuPy-2.0.0b45/MambuPy → MambuPy-2.0.0b47/mambupy}/orm/schema_loans.py +3 -1
  25. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/LICENSE +0 -0
  26. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/__init__.py +0 -0
  27. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/classes.py +0 -0
  28. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/connector/__init__.py +0 -0
  29. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/connector/mambuconnector.py +0 -0
  30. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/interfaces.py +0 -0
  31. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambubranch.py +0 -0
  32. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambucentre.py +0 -0
  33. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambuclient.py +0 -0
  34. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambucustomfield.py +0 -0
  35. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambugroup.py +0 -0
  36. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mamburole.py +0 -0
  37. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/mambutask.py +0 -0
  38. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/api/vos.py +0 -0
  39. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/mambuconfig.py +0 -0
  40. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/mambugeturl.py +0 -0
  41. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/__init__.py +0 -0
  42. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_activities.py +0 -0
  43. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_addresses.py +0 -0
  44. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_branches.py +0 -0
  45. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_clients.py +0 -0
  46. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_customfields.py +0 -0
  47. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_dummies.py +0 -0
  48. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_groups.py +0 -0
  49. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_mambu.py +0 -0
  50. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_orm.py +0 -0
  51. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_tasks.py +0 -0
  52. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/orm/schema_users.py +0 -0
  53. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/__init__.py +0 -0
  54. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambubranch.py +0 -0
  55. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambucentre.py +0 -0
  56. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambuclient.py +0 -0
  57. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambugroup.py +0 -0
  58. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambuloan.py +0 -0
  59. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambuproduct.py +0 -0
  60. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mamburepayment.py +0 -0
  61. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambustruct.py +0 -0
  62. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambutask.py +0 -0
  63. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambutransaction.py +0 -0
  64. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/rest1to2/mambuuser.py +0 -0
  65. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/utils/__init__.py +0 -0
  66. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/utils/logging_config.py +0 -0
  67. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy/utils/userdeactivate.py +0 -0
  68. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy.egg-info/SOURCES.txt +0 -0
  69. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy.egg-info/dependency_links.txt +0 -0
  70. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy.egg-info/requires.txt +0 -0
  71. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/MambuPy.egg-info/top_level.txt +0 -0
  72. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/README.md +0 -0
  73. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/__init__.py +0 -0
  74. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/classes.py +0 -0
  75. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/connector/__init__.py +0 -0
  76. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/connector/mambuconnector.py +0 -0
  77. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/interfaces.py +0 -0
  78. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambubranch.py +0 -0
  79. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambucentre.py +0 -0
  80. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambuclient.py +0 -0
  81. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambucustomfield.py +0 -0
  82. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambugroup.py +0 -0
  83. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mamburole.py +0 -0
  84. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/mambutask.py +0 -0
  85. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/api/vos.py +0 -0
  86. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/mambuconfig.py +0 -0
  87. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/mambugeturl.py +0 -0
  88. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/__init__.py +0 -0
  89. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_activities.py +0 -0
  90. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_addresses.py +0 -0
  91. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_branches.py +0 -0
  92. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_clients.py +0 -0
  93. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_customfields.py +0 -0
  94. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_dummies.py +0 -0
  95. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_groups.py +0 -0
  96. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_mambu.py +0 -0
  97. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_orm.py +0 -0
  98. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_tasks.py +0 -0
  99. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/orm/schema_users.py +0 -0
  100. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/__init__.py +0 -0
  101. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambubranch.py +0 -0
  102. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambucentre.py +0 -0
  103. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambuclient.py +0 -0
  104. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambugroup.py +0 -0
  105. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambuloan.py +0 -0
  106. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambuproduct.py +0 -0
  107. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mamburepayment.py +0 -0
  108. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambustruct.py +0 -0
  109. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambutask.py +0 -0
  110. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambutransaction.py +0 -0
  111. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/rest1to2/mambuuser.py +0 -0
  112. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/utils/__init__.py +0 -0
  113. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/utils/logging_config.py +0 -0
  114. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/mambupy/utils/userdeactivate.py +0 -0
  115. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/setup.cfg +0 -0
  116. {MambuPy-2.0.0b45 → MambuPy-2.0.0b47}/setup.py +0 -0
@@ -35,5 +35,5 @@ TODOS
35
35
  to achive TDD when implementing features or correcting bugs.
36
36
  """
37
37
 
38
- __version__ = "2.0.0b45"
38
+ __version__ = "2.0.0b47"
39
39
  """The version of this module."""
@@ -130,7 +130,7 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
130
130
  url %s, params %s, data %s, headers %s",
131
131
  method,
132
132
  url,
133
- params,
133
+ [(k, v) for k, v in params.items() if k not in ["pwd"]],
134
134
  data,
135
135
  [(k, v) for k, v in headers.items() if k != "Authorization"],
136
136
  )
@@ -263,10 +263,13 @@ class MambuEntity(MambuStruct):
263
263
  minutes = remainder // 60
264
264
  seconds = round(remainder - (minutes * 60), 2)
265
265
  if debug:
266
- print(
267
- "{}-{} ({}) {}:{}:{}".format(
266
+ if elements:
267
+ print("{}-{}".format(
268
268
  elements[0].__class__.__name__,
269
269
  elements[0]["id"],
270
+ ))
271
+ print(
272
+ "({}) {}:{}:{}".format(
270
273
  len(elements),
271
274
  int(hours),
272
275
  int(minutes),
@@ -334,7 +337,7 @@ class MambuEntity(MambuStruct):
334
337
 
335
338
  return instance
336
339
 
337
- def refresh(self, detailsLevel=""):
340
+ def refresh(self, detailsLevel="", **kwargs):
338
341
  """get again this single entity, identified by its entid.
339
342
 
340
343
  Updates _attrs with responded data. Loses any change on _attrs that
@@ -343,6 +346,8 @@ class MambuEntity(MambuStruct):
343
346
 
344
347
  Args:
345
348
  detailsLevel (str BASIC/FULL): ask for extra details or not
349
+ kwargs (dict): keyword arguments for this method.
350
+ May include a user, pwd and url to connect to Mambu.
346
351
  """
347
352
  if not detailsLevel:
348
353
  detailsLevel = self._detailsLevel
@@ -673,7 +678,7 @@ class MambuEntityAttachable(MambuStruct, MambuAttachable):
673
678
  _attachments = {}
674
679
  """dict of attachments of an entity, key is the id"""
675
680
 
676
- def attach_document(self, filename, title="", notes=""):
681
+ def attach_document(self, filename, title="", notes="", **kwargs):
677
682
  """uploads an attachment to this entity
678
683
 
679
684
  _attachments dicitionary gets a new entry with the attached document.
@@ -888,7 +893,14 @@ class MambuEntityCF(MambuValueObject):
888
893
 
889
894
 
890
895
  class MambuInstallment(MambuStruct):
891
- """Loan Account Installment (aka Repayment)"""
896
+ """Loan Account Installment (aka Repayment).
897
+
898
+ Defaults dueDate to UTC since timezone is not relevant for this entity.
899
+ """
900
+
901
+ def __init__(self, **kwargs):
902
+ super().__init__(**kwargs)
903
+ self._as_utc = True
892
904
 
893
905
  def __repr__(self):
894
906
  """repr tells the class name, the number, the state and the dueDate"""
@@ -115,7 +115,7 @@ class MambuLoan(
115
115
  except KeyError:
116
116
  pass
117
117
 
118
- def get_schedule(self):
118
+ def get_schedule(self, **kwargs):
119
119
  """Retrieves the installments schedule."""
120
120
  resp = self._connector.mambu_loanaccount_getSchedule(self.id)
121
121
 
@@ -128,11 +128,11 @@ class MambuLoan(
128
128
  installment_entity._convertDict2Attrs()
129
129
  self.schedule.append(installment_entity)
130
130
 
131
- def get_transactions(self):
131
+ def get_transactions(self, **kwargs):
132
132
  """Retrieves the transactions of the loan"""
133
133
  self.transactions = MambuTransaction.get_all(self.id)
134
134
 
135
- def set_state(self, action, notes):
135
+ def set_state(self, action, notes, **kwargs):
136
136
  """Request to change status of a MambuLoan
137
137
 
138
138
  Args:
@@ -144,7 +144,7 @@ class MambuLoan(
144
144
  """
145
145
  if action in self._accepted_actions:
146
146
  resp = self._connector.mambu_change_state(
147
- entid=self.id, prefix=self._prefix, action=action, notes=notes
147
+ entid=self.id, prefix=self._prefix, action=action, notes=notes,
148
148
  )
149
149
  resp = json.loads(resp)
150
150
  self.accountState = resp["accountState"]
@@ -155,13 +155,13 @@ class MambuLoan(
155
155
  )
156
156
  )
157
157
 
158
- def approve(self, notes):
158
+ def approve(self, notes, **kwargs):
159
159
  """Request to approve a loan account.
160
160
 
161
161
  Args:
162
162
  notes (str): notes to attach to the approval operation.
163
163
  """
164
- self.set_state("APPROVE", notes)
164
+ self.set_state("APPROVE", notes, **kwargs)
165
165
 
166
166
  def disburse(self, notes, firstRepaymentDate=None, disbursementDate=None, **kwargs):
167
167
  """Request to disburse a loan account.
@@ -225,23 +225,23 @@ class MambuLoan(
225
225
 
226
226
  self.refresh()
227
227
 
228
- def reject(self, notes):
228
+ def reject(self, notes, **kwargs):
229
229
  """Request to reject a loan account.
230
230
 
231
231
  Args:
232
232
  notes (str): notes to attach to the reject operation.
233
233
  """
234
- self.set_state("REJECT", notes)
234
+ self.set_state("REJECT", notes, **kwargs)
235
235
 
236
- def close(self, notes):
236
+ def close(self, notes, **kwargs):
237
237
  """Request to close a loan account.
238
238
 
239
239
  Args:
240
240
  notes (str): notes to attach to the closing operation.
241
241
  """
242
- self.set_state("CLOSE", notes)
242
+ self.set_state("CLOSE", notes, **kwargs)
243
243
 
244
- def writeoff(self, notes):
244
+ def writeoff(self, notes, **kwargs):
245
245
  """Request to writeoff a loan account.
246
246
 
247
247
  Args:
@@ -282,6 +282,23 @@ class MambuLoan(
282
282
 
283
283
  self.refresh()
284
284
 
285
+ def adjust_transaction(self, transactionId, notes, **kwargs):
286
+ """Request to adjust a loan transaction.
287
+
288
+ Args:
289
+ transactionId (str): the id of the transaction to adjust
290
+ notes (str): notes to attach to the adjusting transaction.
291
+ """
292
+ if hasattr(self, "transactions"):
293
+ if transactionId not in [t.id for t in self.transactions]:
294
+ raise MambuPyError(
295
+ "transactionId '{}' not found in loan transactions".format(
296
+ transactionId
297
+ )
298
+ )
299
+ self._connector.mambu_loantransaction_adjust(transactionId, notes)
300
+ self.refresh()
301
+
285
302
  def apply_fee(self, amount, installmentNumber, notes, valueDate, **kwargs):
286
303
  """Request to apply a fee to a loan account.
287
304
 
@@ -69,7 +69,7 @@ class MambuProduct(
69
69
 
70
70
  @classmethod
71
71
  def get_all(
72
- cls, filters=None, offset=None, limit=None, paginationDetails="OFF", sortBy=None
72
+ cls, filters=None, offset=None, limit=None, paginationDetails="OFF", sortBy=None, **kwargs
73
73
  ):
74
74
  """get_all, several entities, filtering allowed
75
75
 
@@ -85,6 +85,8 @@ class MambuProduct(
85
85
  Returns:
86
86
  list of instances of an entity with data from Mambu
87
87
  """
88
+ if "detailsLevel" in kwargs:
89
+ kwargs.pop("detailsLevel")
88
90
  return super().get_all(
89
- filters, offset, limit, paginationDetails, detailsLevel="FULL", sortBy=sortBy
91
+ filters, offset, limit, paginationDetails, detailsLevel="FULL", sortBy=sortBy, **kwargs
90
92
  )
@@ -47,6 +47,9 @@ class MambuStruct(MambuMapObj):
47
47
  so those fileds get a None TZ info.
48
48
  """
49
49
 
50
+ _as_utc = False
51
+ """When True, all datetimes will be converted as UTC in _convertDict2Attrs."""
52
+
50
53
  _vos = []
51
54
  """List of Value Objects in the struct's _attrs.
52
55
 
@@ -177,7 +180,7 @@ class MambuStruct(MambuMapObj):
177
180
  return f_data
178
181
  except (TypeError, ValueError):
179
182
  try:
180
- return date_format(data)
183
+ return date_format(data, as_utc=self._as_utc)
181
184
  except (TypeError, ValueError):
182
185
  return data
183
186
 
@@ -195,7 +198,7 @@ class MambuStruct(MambuMapObj):
195
198
  - int: an int number
196
199
  - float: a floating point number
197
200
  - datetime: if the string holds a valid datetime in a date_format
198
- specific format
201
+ specific format. Considers UTC if _as_utc is True.
199
202
 
200
203
  A list of fields that should stay as-they-come (strings) is supported.
201
204
  All fields whose name ends with "Key" is also ignored.
@@ -28,6 +28,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
28
28
  limit=None,
29
29
  paginationDetails="OFF",
30
30
  detailsLevel="BASIC",
31
+ **kwargs,
31
32
  ):
32
33
  """get_all, several transactions, filtering allowed
33
34
 
@@ -41,6 +42,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
41
42
  Returns:
42
43
  list of instances of a transaction with data from Mambu
43
44
  """
45
+ kwargs.update({"prefix": "loans/{}/transactions".format(loanAccountId)})
44
46
  return super().get_all(
45
47
  filters=None,
46
48
  offset=offset,
@@ -48,7 +50,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
48
50
  paginationDetails=paginationDetails,
49
51
  detailsLevel=detailsLevel,
50
52
  sortBy=None,
51
- **{"prefix": "loans/{}/transactions".format(loanAccountId)}
53
+ **kwargs,
52
54
  )
53
55
 
54
56
  def adjust(self, notes):
@@ -80,6 +80,7 @@ class MambuUser(
80
80
  detailsLevel="BASIC",
81
81
  sortBy=None,
82
82
  branchIdType=None,
83
+ **kwargs,
83
84
  ):
84
85
  """get_all, several entities, filtering allowed
85
86
 
@@ -106,6 +107,7 @@ class MambuUser(
106
107
  params = {}
107
108
  if branchIdType:
108
109
  params["branchIdType"] = branchIdType
110
+ params.update(kwargs)
109
111
 
110
112
  return super().get_all(
111
113
  filters, offset, limit, paginationDetails, detailsLevel, sortBy, **params
@@ -34,7 +34,7 @@ except NameError:
34
34
  import json
35
35
  import sys
36
36
 
37
- from datetime import datetime
37
+ from datetime import datetime, timezone
38
38
 
39
39
  API_RETURN_CODES = {
40
40
  "SUCCESS": 0,
@@ -159,7 +159,7 @@ class MambuCommError(MambuError):
159
159
 
160
160
 
161
161
  ### More utility functions follow ###
162
- def date_format(field, formato=None):
162
+ def date_format(field, formato=None, as_utc=False):
163
163
  """Converts a datetime field to a datetime using some specified format.
164
164
 
165
165
  What this really means is that, if specified format includes only for
@@ -170,6 +170,8 @@ def date_format(field, formato=None):
170
170
  A useful format may be %Y%m%d, then the datetime objects effectively
171
171
  translates into date objects alone, with no relevant time information.
172
172
 
173
+ When as_utc is True, the datetime object is converted to UTC timezone.
174
+
173
175
  PLEASE BE AWARE, that this may lose useful information for your datetimes
174
176
  from Mambu. Read this for why this may be a BAD idea:
175
177
  https://julien.danjou.info/blog/2015/python-and-timezones
@@ -184,10 +186,15 @@ def date_format(field, formato=None):
184
186
  formato,
185
187
  )
186
188
  else:
187
- return datetime.strptime(
189
+ field_as_dt = datetime.strptime(
188
190
  datetime.fromisoformat(field).strftime(formato),
189
191
  formato,
190
192
  )
193
+ if as_utc:
194
+ field_as_dt = field_as_dt.astimezone(
195
+ timezone.utc
196
+ ).replace(tzinfo=None)
197
+ return field_as_dt
191
198
 
192
199
 
193
200
  def strip_tags(html):
@@ -38,6 +38,7 @@ class Centre(Base):
38
38
 
39
39
  # Relationships
40
40
  assignedBranchKey = Column(String, ForeignKey(Branch.encodedKey))
41
+ loans = relationship("LoanAccount", back_populates="centre")
41
42
  branch = relationship(Branch, back_populates="centres")
42
43
  groups = relationship("Group", back_populates="centre")
43
44
 
@@ -13,6 +13,7 @@ from sqlalchemy.orm import relationship
13
13
 
14
14
  from . import schema_orm as orm
15
15
  from .schema_branches import Branch
16
+ from .schema_centres import Centre
16
17
  from .schema_users import User
17
18
 
18
19
  dbname = orm.dbname
@@ -89,7 +90,6 @@ class LoanAccount(Base):
89
90
  approvedDate = Column(DateTime)
90
91
  closedDate = Column(DateTime)
91
92
  rescheduledAccountKey = Column(String)
92
- assignedCentreKey = Column(String) # not in API
93
93
  lastSetToArrearsDate = Column(DateTime) # not in API
94
94
 
95
95
  # Relationships
@@ -99,6 +99,8 @@ class LoanAccount(Base):
99
99
  disbursementDetails = relationship("DisbursementDetails")
100
100
  assignedBranchKey = Column(String, ForeignKey(Branch.encodedKey))
101
101
  branch = relationship("Branch", back_populates="loans")
102
+ assignedCentreKey = Column(String, ForeignKey(Centre.encodedKey))
103
+ centre = relationship("Centre", back_populates="loans")
102
104
  assignedUserKey = Column(String, ForeignKey(User.encodedKey))
103
105
  user = relationship("User", back_populates="loans")
104
106
  accountHolderKey = Column(String)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MambuPy
3
- Version: 2.0.0b45
3
+ Version: 2.0.0b47
4
4
  Summary: A python lib for using Mambu APIs.
5
5
  Home-page: https://mambupydocs.readthedocs.io
6
6
  Author: Javier Novoa C.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MambuPy
3
- Version: 2.0.0b45
3
+ Version: 2.0.0b47
4
4
  Summary: A python lib for using Mambu APIs.
5
5
  Home-page: https://mambupydocs.readthedocs.io
6
6
  Author: Javier Novoa C.
@@ -35,5 +35,5 @@ TODOS
35
35
  to achive TDD when implementing features or correcting bugs.
36
36
  """
37
37
 
38
- __version__ = "2.0.0b45"
38
+ __version__ = "2.0.0b47"
39
39
  """The version of this module."""
@@ -130,7 +130,7 @@ class MambuConnectorREST(MambuConnector, MambuConnectorReader, MambuConnectorWri
130
130
  url %s, params %s, data %s, headers %s",
131
131
  method,
132
132
  url,
133
- params,
133
+ [(k, v) for k, v in params.items() if k not in ["pwd"]],
134
134
  data,
135
135
  [(k, v) for k, v in headers.items() if k != "Authorization"],
136
136
  )
@@ -263,10 +263,13 @@ class MambuEntity(MambuStruct):
263
263
  minutes = remainder // 60
264
264
  seconds = round(remainder - (minutes * 60), 2)
265
265
  if debug:
266
- print(
267
- "{}-{} ({}) {}:{}:{}".format(
266
+ if elements:
267
+ print("{}-{}".format(
268
268
  elements[0].__class__.__name__,
269
269
  elements[0]["id"],
270
+ ))
271
+ print(
272
+ "({}) {}:{}:{}".format(
270
273
  len(elements),
271
274
  int(hours),
272
275
  int(minutes),
@@ -334,7 +337,7 @@ class MambuEntity(MambuStruct):
334
337
 
335
338
  return instance
336
339
 
337
- def refresh(self, detailsLevel=""):
340
+ def refresh(self, detailsLevel="", **kwargs):
338
341
  """get again this single entity, identified by its entid.
339
342
 
340
343
  Updates _attrs with responded data. Loses any change on _attrs that
@@ -343,6 +346,8 @@ class MambuEntity(MambuStruct):
343
346
 
344
347
  Args:
345
348
  detailsLevel (str BASIC/FULL): ask for extra details or not
349
+ kwargs (dict): keyword arguments for this method.
350
+ May include a user, pwd and url to connect to Mambu.
346
351
  """
347
352
  if not detailsLevel:
348
353
  detailsLevel = self._detailsLevel
@@ -673,7 +678,7 @@ class MambuEntityAttachable(MambuStruct, MambuAttachable):
673
678
  _attachments = {}
674
679
  """dict of attachments of an entity, key is the id"""
675
680
 
676
- def attach_document(self, filename, title="", notes=""):
681
+ def attach_document(self, filename, title="", notes="", **kwargs):
677
682
  """uploads an attachment to this entity
678
683
 
679
684
  _attachments dicitionary gets a new entry with the attached document.
@@ -888,7 +893,14 @@ class MambuEntityCF(MambuValueObject):
888
893
 
889
894
 
890
895
  class MambuInstallment(MambuStruct):
891
- """Loan Account Installment (aka Repayment)"""
896
+ """Loan Account Installment (aka Repayment).
897
+
898
+ Defaults dueDate to UTC since timezone is not relevant for this entity.
899
+ """
900
+
901
+ def __init__(self, **kwargs):
902
+ super().__init__(**kwargs)
903
+ self._as_utc = True
892
904
 
893
905
  def __repr__(self):
894
906
  """repr tells the class name, the number, the state and the dueDate"""
@@ -115,7 +115,7 @@ class MambuLoan(
115
115
  except KeyError:
116
116
  pass
117
117
 
118
- def get_schedule(self):
118
+ def get_schedule(self, **kwargs):
119
119
  """Retrieves the installments schedule."""
120
120
  resp = self._connector.mambu_loanaccount_getSchedule(self.id)
121
121
 
@@ -128,11 +128,11 @@ class MambuLoan(
128
128
  installment_entity._convertDict2Attrs()
129
129
  self.schedule.append(installment_entity)
130
130
 
131
- def get_transactions(self):
131
+ def get_transactions(self, **kwargs):
132
132
  """Retrieves the transactions of the loan"""
133
133
  self.transactions = MambuTransaction.get_all(self.id)
134
134
 
135
- def set_state(self, action, notes):
135
+ def set_state(self, action, notes, **kwargs):
136
136
  """Request to change status of a MambuLoan
137
137
 
138
138
  Args:
@@ -144,7 +144,7 @@ class MambuLoan(
144
144
  """
145
145
  if action in self._accepted_actions:
146
146
  resp = self._connector.mambu_change_state(
147
- entid=self.id, prefix=self._prefix, action=action, notes=notes
147
+ entid=self.id, prefix=self._prefix, action=action, notes=notes,
148
148
  )
149
149
  resp = json.loads(resp)
150
150
  self.accountState = resp["accountState"]
@@ -155,13 +155,13 @@ class MambuLoan(
155
155
  )
156
156
  )
157
157
 
158
- def approve(self, notes):
158
+ def approve(self, notes, **kwargs):
159
159
  """Request to approve a loan account.
160
160
 
161
161
  Args:
162
162
  notes (str): notes to attach to the approval operation.
163
163
  """
164
- self.set_state("APPROVE", notes)
164
+ self.set_state("APPROVE", notes, **kwargs)
165
165
 
166
166
  def disburse(self, notes, firstRepaymentDate=None, disbursementDate=None, **kwargs):
167
167
  """Request to disburse a loan account.
@@ -225,23 +225,23 @@ class MambuLoan(
225
225
 
226
226
  self.refresh()
227
227
 
228
- def reject(self, notes):
228
+ def reject(self, notes, **kwargs):
229
229
  """Request to reject a loan account.
230
230
 
231
231
  Args:
232
232
  notes (str): notes to attach to the reject operation.
233
233
  """
234
- self.set_state("REJECT", notes)
234
+ self.set_state("REJECT", notes, **kwargs)
235
235
 
236
- def close(self, notes):
236
+ def close(self, notes, **kwargs):
237
237
  """Request to close a loan account.
238
238
 
239
239
  Args:
240
240
  notes (str): notes to attach to the closing operation.
241
241
  """
242
- self.set_state("CLOSE", notes)
242
+ self.set_state("CLOSE", notes, **kwargs)
243
243
 
244
- def writeoff(self, notes):
244
+ def writeoff(self, notes, **kwargs):
245
245
  """Request to writeoff a loan account.
246
246
 
247
247
  Args:
@@ -282,6 +282,23 @@ class MambuLoan(
282
282
 
283
283
  self.refresh()
284
284
 
285
+ def adjust_transaction(self, transactionId, notes, **kwargs):
286
+ """Request to adjust a loan transaction.
287
+
288
+ Args:
289
+ transactionId (str): the id of the transaction to adjust
290
+ notes (str): notes to attach to the adjusting transaction.
291
+ """
292
+ if hasattr(self, "transactions"):
293
+ if transactionId not in [t.id for t in self.transactions]:
294
+ raise MambuPyError(
295
+ "transactionId '{}' not found in loan transactions".format(
296
+ transactionId
297
+ )
298
+ )
299
+ self._connector.mambu_loantransaction_adjust(transactionId, notes)
300
+ self.refresh()
301
+
285
302
  def apply_fee(self, amount, installmentNumber, notes, valueDate, **kwargs):
286
303
  """Request to apply a fee to a loan account.
287
304
 
@@ -69,7 +69,7 @@ class MambuProduct(
69
69
 
70
70
  @classmethod
71
71
  def get_all(
72
- cls, filters=None, offset=None, limit=None, paginationDetails="OFF", sortBy=None
72
+ cls, filters=None, offset=None, limit=None, paginationDetails="OFF", sortBy=None, **kwargs
73
73
  ):
74
74
  """get_all, several entities, filtering allowed
75
75
 
@@ -85,6 +85,8 @@ class MambuProduct(
85
85
  Returns:
86
86
  list of instances of an entity with data from Mambu
87
87
  """
88
+ if "detailsLevel" in kwargs:
89
+ kwargs.pop("detailsLevel")
88
90
  return super().get_all(
89
- filters, offset, limit, paginationDetails, detailsLevel="FULL", sortBy=sortBy
91
+ filters, offset, limit, paginationDetails, detailsLevel="FULL", sortBy=sortBy, **kwargs
90
92
  )
@@ -47,6 +47,9 @@ class MambuStruct(MambuMapObj):
47
47
  so those fileds get a None TZ info.
48
48
  """
49
49
 
50
+ _as_utc = False
51
+ """When True, all datetimes will be converted as UTC in _convertDict2Attrs."""
52
+
50
53
  _vos = []
51
54
  """List of Value Objects in the struct's _attrs.
52
55
 
@@ -177,7 +180,7 @@ class MambuStruct(MambuMapObj):
177
180
  return f_data
178
181
  except (TypeError, ValueError):
179
182
  try:
180
- return date_format(data)
183
+ return date_format(data, as_utc=self._as_utc)
181
184
  except (TypeError, ValueError):
182
185
  return data
183
186
 
@@ -195,7 +198,7 @@ class MambuStruct(MambuMapObj):
195
198
  - int: an int number
196
199
  - float: a floating point number
197
200
  - datetime: if the string holds a valid datetime in a date_format
198
- specific format
201
+ specific format. Considers UTC if _as_utc is True.
199
202
 
200
203
  A list of fields that should stay as-they-come (strings) is supported.
201
204
  All fields whose name ends with "Key" is also ignored.
@@ -28,6 +28,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
28
28
  limit=None,
29
29
  paginationDetails="OFF",
30
30
  detailsLevel="BASIC",
31
+ **kwargs,
31
32
  ):
32
33
  """get_all, several transactions, filtering allowed
33
34
 
@@ -41,6 +42,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
41
42
  Returns:
42
43
  list of instances of a transaction with data from Mambu
43
44
  """
45
+ kwargs.update({"prefix": "loans/{}/transactions".format(loanAccountId)})
44
46
  return super().get_all(
45
47
  filters=None,
46
48
  offset=offset,
@@ -48,7 +50,7 @@ class MambuTransaction(MambuEntity, MambuEntitySearchable):
48
50
  paginationDetails=paginationDetails,
49
51
  detailsLevel=detailsLevel,
50
52
  sortBy=None,
51
- **{"prefix": "loans/{}/transactions".format(loanAccountId)}
53
+ **kwargs,
52
54
  )
53
55
 
54
56
  def adjust(self, notes):
@@ -80,6 +80,7 @@ class MambuUser(
80
80
  detailsLevel="BASIC",
81
81
  sortBy=None,
82
82
  branchIdType=None,
83
+ **kwargs,
83
84
  ):
84
85
  """get_all, several entities, filtering allowed
85
86
 
@@ -106,6 +107,7 @@ class MambuUser(
106
107
  params = {}
107
108
  if branchIdType:
108
109
  params["branchIdType"] = branchIdType
110
+ params.update(kwargs)
109
111
 
110
112
  return super().get_all(
111
113
  filters, offset, limit, paginationDetails, detailsLevel, sortBy, **params
@@ -34,7 +34,7 @@ except NameError:
34
34
  import json
35
35
  import sys
36
36
 
37
- from datetime import datetime
37
+ from datetime import datetime, timezone
38
38
 
39
39
  API_RETURN_CODES = {
40
40
  "SUCCESS": 0,
@@ -159,7 +159,7 @@ class MambuCommError(MambuError):
159
159
 
160
160
 
161
161
  ### More utility functions follow ###
162
- def date_format(field, formato=None):
162
+ def date_format(field, formato=None, as_utc=False):
163
163
  """Converts a datetime field to a datetime using some specified format.
164
164
 
165
165
  What this really means is that, if specified format includes only for
@@ -170,6 +170,8 @@ def date_format(field, formato=None):
170
170
  A useful format may be %Y%m%d, then the datetime objects effectively
171
171
  translates into date objects alone, with no relevant time information.
172
172
 
173
+ When as_utc is True, the datetime object is converted to UTC timezone.
174
+
173
175
  PLEASE BE AWARE, that this may lose useful information for your datetimes
174
176
  from Mambu. Read this for why this may be a BAD idea:
175
177
  https://julien.danjou.info/blog/2015/python-and-timezones
@@ -184,10 +186,15 @@ def date_format(field, formato=None):
184
186
  formato,
185
187
  )
186
188
  else:
187
- return datetime.strptime(
189
+ field_as_dt = datetime.strptime(
188
190
  datetime.fromisoformat(field).strftime(formato),
189
191
  formato,
190
192
  )
193
+ if as_utc:
194
+ field_as_dt = field_as_dt.astimezone(
195
+ timezone.utc
196
+ ).replace(tzinfo=None)
197
+ return field_as_dt
191
198
 
192
199
 
193
200
  def strip_tags(html):
@@ -38,6 +38,7 @@ class Centre(Base):
38
38
 
39
39
  # Relationships
40
40
  assignedBranchKey = Column(String, ForeignKey(Branch.encodedKey))
41
+ loans = relationship("LoanAccount", back_populates="centre")
41
42
  branch = relationship(Branch, back_populates="centres")
42
43
  groups = relationship("Group", back_populates="centre")
43
44
 
@@ -13,6 +13,7 @@ from sqlalchemy.orm import relationship
13
13
 
14
14
  from . import schema_orm as orm
15
15
  from .schema_branches import Branch
16
+ from .schema_centres import Centre
16
17
  from .schema_users import User
17
18
 
18
19
  dbname = orm.dbname
@@ -89,7 +90,6 @@ class LoanAccount(Base):
89
90
  approvedDate = Column(DateTime)
90
91
  closedDate = Column(DateTime)
91
92
  rescheduledAccountKey = Column(String)
92
- assignedCentreKey = Column(String) # not in API
93
93
  lastSetToArrearsDate = Column(DateTime) # not in API
94
94
 
95
95
  # Relationships
@@ -99,6 +99,8 @@ class LoanAccount(Base):
99
99
  disbursementDetails = relationship("DisbursementDetails")
100
100
  assignedBranchKey = Column(String, ForeignKey(Branch.encodedKey))
101
101
  branch = relationship("Branch", back_populates="loans")
102
+ assignedCentreKey = Column(String, ForeignKey(Centre.encodedKey))
103
+ centre = relationship("Centre", back_populates="loans")
102
104
  assignedUserKey = Column(String, ForeignKey(User.encodedKey))
103
105
  user = relationship("User", back_populates="loans")
104
106
  accountHolderKey = Column(String)
File without changes
File without changes
File without changes
File without changes