trex-model 1.2.19__tar.gz → 1.3.1__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.

Potentially problematic release.


This version of trex-model might be problematic. Click here for more details.

Files changed (59) hide show
  1. {trex-model-1.2.19 → trex-model-1.3.1}/PKG-INFO +1 -1
  2. {trex-model-1.2.19 → trex-model-1.3.1}/setup.py +1 -1
  3. {trex-model-1.2.19 → trex-model-1.3.1}/trex_model.egg-info/PKG-INFO +1 -1
  4. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/conf.py +5 -2
  5. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/loyalty_models.py +50 -1
  6. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/message_model_helper.py +162 -47
  7. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/message_models.py +7 -3
  8. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/prepaid_models.py +158 -2
  9. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/redeem_models.py +15 -5
  10. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/program_conf.py +2 -0
  11. {trex-model-1.2.19 → trex-model-1.3.1}/LICENSE +0 -0
  12. {trex-model-1.2.19 → trex-model-1.3.1}/MANIFEST.in +0 -0
  13. {trex-model-1.2.19 → trex-model-1.3.1}/README.md +0 -0
  14. {trex-model-1.2.19 → trex-model-1.3.1}/setup.cfg +0 -0
  15. {trex-model-1.2.19 → trex-model-1.3.1}/trex_model.egg-info/SOURCES.txt +0 -0
  16. {trex-model-1.2.19 → trex-model-1.3.1}/trex_model.egg-info/dependency_links.txt +0 -0
  17. {trex-model-1.2.19 → trex-model-1.3.1}/trex_model.egg-info/requires.txt +0 -0
  18. {trex-model-1.2.19 → trex-model-1.3.1}/trex_model.egg-info/top_level.txt +0 -0
  19. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/__init__.py +0 -0
  20. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/__init__.py +0 -0
  21. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/__init__.py +0 -0
  22. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/admin_models.py +0 -0
  23. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/analytic_models.py +0 -0
  24. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/app_models.py +0 -0
  25. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/coporate_models.py +0 -0
  26. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/customer_model_helpers.py +0 -0
  27. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/customer_models.py +0 -0
  28. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/fb_subsriber_models.py +0 -0
  29. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/import_models.py +0 -0
  30. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/inventory_model.py +0 -0
  31. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/lucky_draw_models.py +0 -0
  32. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/marketing_models.py +0 -0
  33. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/membership_models.py +0 -0
  34. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/merchant_models.py +0 -0
  35. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/model_decorators.py +0 -0
  36. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/ndb_models.py +0 -0
  37. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/pos_models.py +0 -0
  38. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/product_models.py +0 -0
  39. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/program_models.py +0 -0
  40. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/rating_models.py +0 -0
  41. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/redemption_catalogue_models.py +0 -0
  42. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/reward_model_helpers.py +0 -0
  43. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/reward_models.py +0 -0
  44. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/spending_base_program_model.py +0 -0
  45. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/system_models.py +0 -0
  46. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/task_models.py +0 -0
  47. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/test_models.py +0 -0
  48. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/transaction_models.py +0 -0
  49. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/user_models.py +0 -0
  50. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/datastore/voucher_models.py +0 -0
  51. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/merchant_helpers.py +0 -0
  52. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/model_decorator.py +0 -0
  53. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/models/prepaid_helpers.py +0 -0
  54. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/pos_conf.py +0 -0
  55. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/utils/__init__.py +0 -0
  56. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/utils/gcloud/__init__.py +0 -0
  57. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/utils/gcloud/datastore_util.py +0 -0
  58. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/utils/model/__init__.py +0 -0
  59. {trex-model-1.2.19 → trex-model-1.3.1}/trexmodel/utils/model/model_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: trex-model
3
- Version: 1.2.19
3
+ Version: 1.3.1
4
4
  Summary: TRex database module package
5
5
  Home-page: https://bitbucket.org/lokjac/trex-model
6
6
  Author: Jack Lok
@@ -3,7 +3,7 @@ with open("README.md", "r") as fh:
3
3
  long_description = fh.read()
4
4
  setuptools.setup(
5
5
  name='trex-model',
6
- version='1.2.19',
6
+ version='1.3.1',
7
7
  author="Jack Lok",
8
8
  author_email="sglok77@gmail.com",
9
9
  description="TRex database module package",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: trex-model
3
- Version: 1.2.19
3
+ Version: 1.3.1
4
4
  Summary: TRex database module package
5
5
  Home-page: https://bitbucket.org/lokjac/trex-model
6
6
  Author: Jack Lok
@@ -7,7 +7,7 @@ MAX_FETCH_RECORD_FULL_TEXT_SEARCH_PER_PAGE = 10
7
7
  MAX_FETCH_RECORD = 99999999
8
8
  MAX_FETCH_IMAGE_RECORD = 100
9
9
  MAX_CHAR_RANDOM_UUID4 = 20
10
- PAGINATION_SIZE = 2
10
+ PAGINATION_SIZE = 10
11
11
  VISIBLE_PAGE_COUNT = 10
12
12
 
13
13
  DEFAULT_GMT_HOURS = 8
@@ -34,8 +34,9 @@ MESSAGE_CATEGORY_PROMOTION = 'promotion'
34
34
  MESSAGE_CATEGORY_SURVEY = 'survey'
35
35
  MESSAGE_CATEGORY_SYSTEM = 'system'
36
36
  MESSAGE_CATEGORY_REWARD = 'reward'
37
+ MESSAGE_CATEGORY_REDEEM = 'redeem'
37
38
 
38
- MESSAGE_CATEGORIES = (MESSAGE_CATEGORY_ANNOUNCEMENT, MESSAGE_CATEGORY_ALERT, MESSAGE_CATEGORY_PROMOTION, MESSAGE_CATEGORY_SURVEY, MESSAGE_CATEGORY_SYSTEM, MESSAGE_CATEGORY_REWARD)
39
+ MESSAGE_CATEGORIES = (MESSAGE_CATEGORY_ANNOUNCEMENT, MESSAGE_CATEGORY_ALERT, MESSAGE_CATEGORY_PROMOTION, MESSAGE_CATEGORY_SURVEY, MESSAGE_CATEGORY_SYSTEM, MESSAGE_CATEGORY_REWARD, MESSAGE_CATEGORY_REDEEM)
39
40
 
40
41
  MESSAGE_STATUS_NEW = 'n'
41
42
  MESSAGE_STATUS_READ = 'r'
@@ -50,3 +51,5 @@ USER_STATUS_SET = (USER_STATUS_REGISTERED, USER_STATUS_ENTER_BIODATA, USER_STATU
50
51
 
51
52
  MESSAGE_STATUS_SET = (MESSAGE_STATUS_NEW, MESSAGE_STATUS_READ)
52
53
 
54
+ PREPAID_REDEEM_URL = os.environ['PREPAID_REDEEM_URL']
55
+
@@ -28,9 +28,19 @@ class LoyaltyDeviceSetting(BaseNModel,DictModel):
28
28
  created_datetime = ndb.DateTimeProperty(required=True, auto_now_add=True)
29
29
  activated_datetime = ndb.DateTimeProperty(required=False)
30
30
  testing = ndb.BooleanProperty(required=False, default=False)
31
+ device_details = ndb.JsonProperty()
31
32
 
32
33
  dict_properties = ['device_name', 'activation_code', 'device_id', 'activated', 'assigned_outlet_key',
33
- 'activated_datetime', 'created_datetime']
34
+ 'activated_datetime', 'created_datetime', 'device_details']
35
+
36
+ @property
37
+ def device_tokens_list(self):
38
+ if self.device_details:
39
+ _tokens_list = []
40
+ for k,v in self.device_details.items():
41
+ for dd in v:
42
+ _tokens_list.append(dd.get('device_token'))
43
+ return _tokens_list
34
44
 
35
45
  @property
36
46
  def is_test_setting(self):
@@ -135,3 +145,42 @@ class LoyaltyDeviceSetting(BaseNModel,DictModel):
135
145
  return True
136
146
  else:
137
147
  return False
148
+
149
+ def update_device_details(self, platform, device_token):
150
+ if self.device_details:
151
+ found_device_details_list_by_platform = self.device_details.get(platform)
152
+ if found_device_details_list_by_platform:
153
+ is_found = False
154
+ for device_details_by_platform in found_device_details_list_by_platform:
155
+ device_token_by_platform = device_details_by_platform.get('device_token')
156
+ if device_token_by_platform:
157
+ device_details_by_platform['last_updated_datetime'] = datetime.utcnow().strftime("%d-%m-%Y %H:%M:%S")
158
+ is_found = True
159
+ break
160
+
161
+ if is_found == False:
162
+ found_device_details_list_by_platform.append(
163
+ {
164
+ 'device_token' : device_token,
165
+ 'last_updated_datetime' : datetime.utcnow().strftime("%d-%m-%Y %H:%M:%S"),
166
+ }
167
+ )
168
+
169
+
170
+ else:
171
+ self.device_details[platform] = [
172
+ {
173
+ 'device_token' : device_token,
174
+ 'last_updated_datetime' : datetime.utcnow().strftime("%d-%m-%Y %H:%M:%S"),
175
+ }
176
+ ]
177
+ else:
178
+ self.device_details = {
179
+ platform : [
180
+ {
181
+ 'device_token' : device_token,
182
+ 'last_updated_datetime' : datetime.utcnow().strftime("%d-%m-%Y %H:%M:%S"),
183
+ }
184
+ ]
185
+ }
186
+ self.put()
@@ -5,11 +5,20 @@ Created on 9 Nov 2023
5
5
  '''
6
6
  from trexmodel.program_conf import REWARD_FORMAT_MAP, REWARD_FORMAT_PREPAID
7
7
  from trexmodel.models.datastore.message_models import Message
8
- from trexmodel.conf import MESSAGE_CATEGORY_REWARD, MESSAGE_STATUS_NEW
8
+ from trexmodel.conf import MESSAGE_CATEGORY_REWARD, MESSAGE_STATUS_NEW,\
9
+ MESSAGE_CATEGORY_REDEEM
10
+ from trexmodel import program_conf
11
+ from babel.numbers import format_currency
12
+ import logging
13
+
14
+
15
+ logger = logging.getLogger('helper')
9
16
 
10
17
  entitled_reward_message_template = '''{amount} {reward_format}'''
11
18
 
12
19
  entitled_voucher_message_template = '''{amount} voucher - {label}'''
20
+
21
+ redeemed_voucher_message_template = '''{amount} voucher - {label}'''
13
22
 
14
23
  entitled_lucky_draw_message_template = '''{amount} lucky draw ticket(s)'''
15
24
 
@@ -131,34 +140,70 @@ message_logo_image_template = '''
131
140
 
132
141
 
133
142
  def create_transaction_message(customer_transaction):
134
- user_acct = customer_transaction.transact_user_acct
135
- message = Message(
136
- message_to = user_acct.create_ndb_key(),
137
- title = 'Transaction Reward',
138
- message_category = MESSAGE_CATEGORY_REWARD,
139
- message_content = __create_entiled_message_from_customer_transaction(customer_transaction),
140
- message_data = __create_message_data_from_transaction(customer_transaction),
141
- status = MESSAGE_STATUS_NEW,
142
-
143
- )
144
- message.put()
145
- user_acct.new_message_count+=1
146
- user_acct.put()
143
+ user_acct = customer_transaction.transact_user_acct
144
+ source_key = customer_transaction.key_in_str
145
+ message = Message.get_by_source_key(source_key)
146
+
147
+ if message is None:
148
+ message = Message(
149
+ message_to = user_acct.create_ndb_key(),
150
+ title = 'Transaction Reward',
151
+ message_category = MESSAGE_CATEGORY_REWARD,
152
+ message_content = __create_entiled_message_from_customer_transaction(customer_transaction),
153
+ message_data = __create_message_data_from_transaction(customer_transaction),
154
+ status = MESSAGE_STATUS_NEW,
155
+
156
+ )
157
+ message.put()
158
+ user_acct.new_message_count+=1
159
+ user_acct.put()
160
+
161
+ return message
162
+
163
+ def create_redemption_message(customer_redemption):
164
+ user_acct = customer_redemption.redeemed_user_acct
165
+ merchant_acct = customer_redemption.redeemed_merchant_acct
166
+ source_key = customer_redemption.key_in_str
167
+ message = Message.get_by_source_key(source_key)
168
+
169
+ if message is None:
170
+ message = Message(
171
+ source_key = source_key,
172
+ message_to = user_acct.create_ndb_key(),
173
+ title = 'Redemption',
174
+ message_category = MESSAGE_CATEGORY_REDEEM,
175
+ message_content = __create_message_from_redeem_transaction(merchant_acct, customer_redemption),
176
+ message_data = __create_message_data_from_transaction(customer_redemption),
177
+ status = MESSAGE_STATUS_NEW,
178
+
179
+ )
180
+ message.put()
181
+ user_acct.new_message_count+=1
182
+ user_acct.put()
183
+
184
+ return message
147
185
 
148
186
  def create_redeem_catalogue_item_message(customer, entitled_vouchers_summary, redemption_catalogue_transaction):
149
- user_acct = customer.registered_user_acct
150
- message = Message(
151
- message_to = user_acct.create_ndb_key(),
152
- title = 'Redemption Catalogue Reward',
153
- message_category = MESSAGE_CATEGORY_REWARD,
154
- message_content = __create_message_from_redeem_catalogue_transaction(customer, entitled_vouchers_summary),
155
- message_data = __create_message_data_from_redemption_catalogue(redemption_catalogue_transaction),
156
- status = MESSAGE_STATUS_NEW,
157
-
158
- )
159
- message.put()
160
- user_acct.new_message_count+=1
161
- user_acct.put()
187
+ user_acct = customer.registered_user_acct
188
+ source_key = redemption_catalogue_transaction.key_in_str
189
+ message = Message.get_by_source_key(source_key)
190
+
191
+ if message is None:
192
+ message = Message(
193
+
194
+ message_to = user_acct.create_ndb_key(),
195
+ title = 'Redemption Catalogue Reward',
196
+ message_category = MESSAGE_CATEGORY_REWARD,
197
+ message_content = __create_message_from_redeem_catalogue_transaction(customer, entitled_vouchers_summary),
198
+ message_data = __create_message_data_from_redemption_catalogue(redemption_catalogue_transaction),
199
+ status = MESSAGE_STATUS_NEW,
200
+
201
+ )
202
+ message.put()
203
+ user_acct.new_message_count+=1
204
+ user_acct.put()
205
+
206
+ return message
162
207
 
163
208
  def __create_message_data_from_transaction(customer_transaction):
164
209
  return {
@@ -201,23 +246,6 @@ def __create_entiled_message_from_customer_transaction(customer_transaction):
201
246
  'font-size' : 20,
202
247
  })
203
248
 
204
- merchant_logo_content = message_logo_image_template.format(merchant_logo= merchant_logo,)
205
- merchant_name = merchant_acct.company_name
206
- '''
207
- html_content = entitled_messages_template.format(
208
- message_list = ''.join(message_list),
209
- merchant_logo = merchant_name,
210
- #message_banner_image = message_banner_image_template,
211
- message_banner_image = '',
212
- #message_congrat_image = message_congrat_image_template,
213
- message_congrat_image = '',
214
- )
215
-
216
- return {
217
- 'type' : 'html',
218
- 'content' : html_content,
219
- }
220
- '''
221
249
  return {
222
250
  'type' : 'json',
223
251
  'content' : {
@@ -287,9 +315,6 @@ def __create_message_from_redeem_catalogue_transaction(customer, entitled_vouche
287
315
  'font-size' : 20,
288
316
  })
289
317
 
290
- merchant_logo_content = message_logo_image_template.format(merchant_logo= merchant_logo,)
291
- merchant_name = merchant_acct.company_name
292
-
293
318
  return {
294
319
  'type' : 'json',
295
320
  'content' : {
@@ -338,7 +363,57 @@ def __create_message_from_redeem_catalogue_transaction(customer, entitled_vouche
338
363
  ]
339
364
  }
340
365
  }
366
+
367
+ def __create_message_from_redeem_transaction(merchant_acct, customer_redemption):
368
+
369
+ messages_list = []
370
+
371
+ message_list = []
372
+ #merchant_logo = merchant_acct.logo_public_url
373
+ brand_name = merchant_acct.brand_name
374
+
375
+ messages_for_json_list = []
376
+
377
+ messages_list.extend(__create_customer_redemption_message(customer_redemption))
341
378
 
379
+ for message in messages_list:
380
+ message_list.append('<li class="pt-2">{message}</li>'.format(message=message))
381
+ messages_for_json_list.append({
382
+ 'type' : 'text',
383
+ 'value' : message,
384
+ 'font-size' : 20,
385
+ })
386
+
387
+ return {
388
+ 'type' : 'json',
389
+ 'content' : {
390
+ 'header':[
391
+ {
392
+ 'type': 'text',
393
+ 'value': 'Redemption'
394
+
395
+ },
396
+ ],
397
+ 'title':[
398
+ {
399
+ 'type':'text',
400
+ 'value': __create_customer_redemption_title(customer_redemption),
401
+ 'font-size': 25,
402
+ }
403
+ ],
404
+
405
+ 'body':messages_for_json_list,
406
+
407
+ 'footer':[
408
+
409
+ {
410
+ 'type':'text',
411
+ 'value': 'To %s' % brand_name,
412
+ 'font-size': 25,
413
+ }
414
+ ]
415
+ }
416
+ }
342
417
 
343
418
  def __create_entitled_reward_message(customer_transaction):
344
419
  entitled_reward_summary = customer_transaction.entitled_reward_summary
@@ -389,6 +464,46 @@ def __create_entitled_voucher_message_from_entitled_voucher_summary(entitled_vou
389
464
 
390
465
  return entitled_messages_list
391
466
 
467
+ def __create_customer_redemption_message(customer_redemption):
468
+ messages_list = []
469
+ if customer_redemption.reward_format == program_conf.FEATURE_CODE_PREPAID_REWARD_FORMAT:
470
+ merchant_acct = customer_redemption.redeemed_merchant_acct
471
+
472
+ logger.debug('redeemed_amount=%d', customer_redemption.redeemed_amount)
473
+ logger.debug('currency_code=%s', merchant_acct.currency_code)
474
+
475
+ formated_redeem_amount = format_currency(customer_redemption.redeemed_amount,
476
+ merchant_acct.currency_code,
477
+ u'#,##0.00',
478
+ locale='en_US',
479
+ currency_digits=False,
480
+ )
481
+ logger.debug('formated_redeem_amount=%s', formated_redeem_amount)
482
+
483
+ messages_list.append("%s prepaid" % (formated_redeem_amount))
484
+
485
+ elif customer_redemption.reward_format == program_conf.FEATURE_CODE_VOUCHER_REWARD_FORMAT:
486
+ redeemed_summary = customer_redemption.redeemed_summary
487
+ redeemed_vouchers_list = redeemed_summary.get('voucher').get('vouchers')
488
+ for voucher_key, voucher_details in redeemed_vouchers_list.items():
489
+
490
+ messages_list.append(
491
+ redeemed_voucher_message_template.format(
492
+ label = voucher_details.get('label'),
493
+ amount = voucher_details.get('amount'),
494
+ )
495
+ )
496
+
497
+ return messages_list
498
+
499
+ def __create_customer_redemption_title(customer_redemption):
500
+
501
+ if customer_redemption.reward_format == program_conf.FEATURE_CODE_PREPAID_REWARD_FORMAT:
502
+ return "You have paid"
503
+
504
+ elif customer_redemption.reward_format == program_conf.FEATURE_CODE_VOUCHER_REWARD_FORMAT:
505
+ return "You have redeemed"
506
+
392
507
  def __create_entitled_lucky_draw_ticket_message(customer_transaction):
393
508
  entitled_lucky_draw_ticket_summary = customer_transaction.entitled_lucky_draw_ticket_summary
394
509
  entitled_messages_list = [
@@ -34,6 +34,7 @@ content_body=[text in html]
34
34
 
35
35
  class Message(BaseNModel, DictModel):
36
36
  message_to = ndb.KeyProperty(name="message_to", kind=User)
37
+ source_key = ndb.StringProperty(required=False)
37
38
  title = ndb.StringProperty(required=True)
38
39
  message_category = ndb.StringProperty(required=True, default=MESSAGE_CATEGORY_SYSTEM, choices=MESSAGE_CATEGORIES)
39
40
  message_content = ndb.JsonProperty(required=True, indexed=False)
@@ -44,7 +45,7 @@ class Message(BaseNModel, DictModel):
44
45
  email_sent_datetime = ndb.DateTimeProperty(required=False)
45
46
 
46
47
  dict_properties = [
47
- 'message_to', 'title', 'message_category', 'message_content', 'message_data', 'status', 'created_datetime'
48
+ 'source_key', 'message_to', 'title', 'message_category', 'message_content', 'message_data', 'status', 'created_datetime'
48
49
  ]
49
50
 
50
51
  @property
@@ -59,8 +60,9 @@ class Message(BaseNModel, DictModel):
59
60
  return CustomerTransaction.fetch(customer_transaction_key)
60
61
 
61
62
  @staticmethod
62
- def create(message_to=None, title=None, message_type=MESSAGE_CATEGORY_ANNOUNCEMENT,message_content={}):
63
+ def create(source_key=None, message_to=None, title=None, message_type=MESSAGE_CATEGORY_ANNOUNCEMENT,message_content={}):
63
64
  Message(
65
+ source_key = source_key,
64
66
  message_to = message_to.create_ndb_key(),
65
67
  title = title,
66
68
  message_type = message_type,
@@ -99,5 +101,7 @@ class Message(BaseNModel, DictModel):
99
101
  return Message.list_all_with_condition_query(query, limit=limit, start_cursor=start_cursor, return_with_cursor=True, keys_only=False)
100
102
 
101
103
 
102
-
104
+ @staticmethod
105
+ def get_by_source_key(source_key):
106
+ return Message.query(ndb.AND(Message.source_key==source_key)).get()
103
107
 
@@ -9,14 +9,16 @@ from trexmodel.models.datastore.user_models import User
9
9
  from trexmodel.models.datastore.merchant_models import MerchantAcct, Outlet, MerchantUser
10
10
  import logging, json
11
11
  from trexmodel import conf, program_conf
12
- from trexlib.utils.string_util import random_string
12
+ from trexlib.utils.string_util import random_string, random_number, is_not_empty
13
13
  from datetime import datetime, timedelta
14
14
  import trexmodel.conf as model_conf
15
15
  from trexlib.utils.common.common_util import sort_dict_list
16
16
  from trexmodel.utils.model.model_util import generate_transaction_id
17
17
  from dateutil.relativedelta import relativedelta
18
+ from trexmodel.program_conf import PRODUCT_TYPES, LOYALTY_PRODUCT
19
+ from trexlib.utils.crypto_util import encrypt
18
20
 
19
- logger = logging.getLogger('debug')
21
+ logger = logging.getLogger('model')
20
22
 
21
23
  class PrepaidSettings(BaseNModel,DictModel):
22
24
  '''
@@ -185,6 +187,160 @@ class PrepaidSettings(BaseNModel,DictModel):
185
187
  merchant_acct.remove_prepaid_program_configuration(prepaid_settings.key_in_str)
186
188
  merchant_acct.put()
187
189
 
190
+ class PrepaidRedeemSettings(BaseNModel,DictModel):
191
+ '''
192
+ Merchant acct as ancestor
193
+ '''
194
+ label = ndb.StringProperty(required=True)
195
+ device_activation_code = ndb.StringProperty(required=True)
196
+ device_type = ndb.StringProperty(required=False, default=LOYALTY_PRODUCT, choices=set(PRODUCT_TYPES))
197
+ assigned_outlet = ndb.KeyProperty(name="assigned_outlet", kind=Outlet)
198
+ testing = ndb.BooleanProperty(required=False, default=False)
199
+
200
+ redeem_code = ndb.StringProperty(required=True)
201
+
202
+ created_datetime = ndb.DateTimeProperty(required=True, auto_now_add=True)
203
+ modified_datetime = ndb.DateTimeProperty(required=True, auto_now=True)
204
+
205
+ created_by = ndb.KeyProperty(name="created_by", kind=MerchantUser)
206
+ created_by_username = ndb.StringProperty(required=False)
207
+ modified_by = ndb.KeyProperty(name="modified_by", kind=MerchantUser)
208
+ modified_by_username = ndb.StringProperty(required=False)
209
+
210
+
211
+ dict_properties = [
212
+ 'label', 'redeem_code', 'redeem_url', 'device_activation_code', 'device_type', 'assigned_outlet_key', 'created_datetime', 'modified_datetime',
213
+ ]
214
+
215
+ @property
216
+ def is_test_setting(self):
217
+ return self.testing
218
+
219
+ @property
220
+ def assigned_outlet_key(self):
221
+ return self.assigned_outlet.urlsafe().decode('utf-8')
222
+
223
+ @property
224
+ def assigned_outlet_entity(self):
225
+ return Outlet.fetch(self.assigned_outlet_key)
226
+
227
+ @property
228
+ def merchant_acct_entity(self):
229
+ return MerchantAcct.fetch(self.key.parent().urlsafe())
230
+
231
+ @property
232
+ def redeem_url(self):
233
+ encrypted_redeem_code = encrypt(self.redeem_code)
234
+ return conf.PREPAID_REDEEM_URL.format(code=encrypted_redeem_code)
235
+
236
+ @property
237
+ def is_loyalty_device(self):
238
+ if self.device_type == program_conf.LOYALTY_PRODUCT:
239
+ return True
240
+ return False
241
+
242
+ @staticmethod
243
+ def create(merchant_acct, label, assigned_outlet, device_activation_code=None, testing=False,
244
+ created_by=None
245
+ ):
246
+
247
+ created_by_username = None
248
+ if is_not_empty(created_by):
249
+ if isinstance(created_by, MerchantUser):
250
+ created_by_username = created_by.username
251
+
252
+ redeem_code = random_number(24)
253
+ checking_redeem_setting = PrepaidRedeemSettings.get_by_redeem_code(redeem_code)
254
+ regenerate_redeem_code = False
255
+
256
+ if checking_redeem_setting:
257
+ regenerate_redeem_code = True
258
+
259
+ while(regenerate_redeem_code):
260
+ redeem_code = random_number(24)
261
+ checking_redeem_setting = PrepaidRedeemSettings.get_by_redeem_code(redeem_code)
262
+ if checking_redeem_setting==None:
263
+ regenerate_redeem_code = False
264
+
265
+ prepaid_redeem_settings = PrepaidRedeemSettings(
266
+ parent = merchant_acct.create_ndb_key(),
267
+ assigned_outlet = assigned_outlet.create_ndb_key(),
268
+ label = label,
269
+ redeem_code = redeem_code,
270
+ testing = testing,
271
+ device_activation_code = device_activation_code,
272
+
273
+ created_by = created_by.create_ndb_key(),
274
+ created_by_username = created_by_username,
275
+ )
276
+
277
+ prepaid_redeem_settings.put()
278
+
279
+ return prepaid_redeem_settings
280
+
281
+ @staticmethod
282
+ def update(prepaid_redeem_settings_key, label, assigned_outlet, device_activation_code=None,
283
+ modified_by=None
284
+ ):
285
+
286
+ modified_by_username = None
287
+ if is_not_empty(modified_by):
288
+ if isinstance(modified_by, MerchantUser):
289
+ modified_by_username = modified_by.username
290
+
291
+ prepaid_redeem_settings = PrepaidRedeemSettings.fetch(prepaid_redeem_settings_key)
292
+
293
+ prepaid_redeem_settings.label = label
294
+ prepaid_redeem_settings.device_activation_code = device_activation_code
295
+ prepaid_redeem_settings.assigned_outlet = assigned_outlet.create_ndb_key()
296
+ prepaid_redeem_settings.modified_by = modified_by.create_ndb_key()
297
+ prepaid_redeem_settings.modified_by_username = modified_by_username
298
+
299
+ prepaid_redeem_settings.put()
300
+
301
+ return prepaid_redeem_settings
302
+
303
+ @staticmethod
304
+ def remove(prepaid_redeem_settings_key):
305
+ prepaid_redeem_settings = PrepaidRedeemSettings.fetch(prepaid_redeem_settings_key)
306
+ if prepaid_redeem_settings:
307
+ prepaid_redeem_settings.delete()
308
+
309
+ @staticmethod
310
+ def get_by_redeem_code(redeem_code):
311
+ return PrepaidRedeemSettings.query(PrepaidRedeemSettings.redeem_code ==redeem_code).get()
312
+
313
+ @staticmethod
314
+ def list_by_merchant_account_and_assigned_outlet(merchant_acct, assigned_outlet, offset=0, limit=conf.PAGINATION_SIZE, start_cursor=None, return_with_cursor=False):
315
+ query = PrepaidRedeemSettings.query(ndb.AND(
316
+ PrepaidRedeemSettings.assigned_outlet==assigned_outlet.create_ndb_key()
317
+ ),ancestor=merchant_acct.create_ndb_key())
318
+
319
+ return PrepaidRedeemSettings.list_all_with_condition_query(query, offset=offset, limit=limit, start_cursor=start_cursor, return_with_cursor=return_with_cursor)
320
+
321
+ @staticmethod
322
+ def count_by_merchant_account_and_assigned_outlet(merchant_acct, assigned_outlet):
323
+ query = PrepaidRedeemSettings.query(ndb.AND(
324
+ PrepaidRedeemSettings.assigned_outlet==assigned_outlet.create_ndb_key()
325
+ ),ancestor=merchant_acct.create_ndb_key())
326
+
327
+ return PrepaidRedeemSettings.count_with_condition_query(query)
328
+
329
+ @staticmethod
330
+ def list_by_merchant_account(merchant_acct, offset=0, limit=conf.PAGINATION_SIZE, start_cursor=None, return_with_cursor=False):
331
+ query = PrepaidRedeemSettings.query(ancestor=merchant_acct.create_ndb_key())
332
+
333
+ return PrepaidRedeemSettings.list_all_with_condition_query(query, offset=offset, limit=limit, start_cursor=start_cursor, return_with_cursor=return_with_cursor)
334
+
335
+ @staticmethod
336
+ def count_by_merchant_acct(merchant_acct):
337
+ if merchant_acct:
338
+ query = PrepaidRedeemSettings.query(ancestor=merchant_acct.create_ndb_key())
339
+ else:
340
+ query = PrepaidRedeemSettings.query()
341
+
342
+ return PrepaidRedeemSettings.count_with_condition_query(query)
343
+
188
344
  class CustomerPrepaidReward(BaseNModel,DictModel):
189
345
  '''
190
346
  Customer acct as ancestor
@@ -62,7 +62,7 @@ class CustomerRedemption(BaseNModel, DictModel):
62
62
  redeemed_amount = ndb.FloatProperty(required=True, default=1)
63
63
 
64
64
  redeemed_summary = ndb.JsonProperty(required=True)
65
-
65
+ prepaid_redeem_code = ndb.StringProperty(required=False)
66
66
  transaction_id = ndb.StringProperty(required=True)
67
67
  invoice_id = ndb.StringProperty(required=False)
68
68
  remarks = ndb.StringProperty(required=False)
@@ -85,7 +85,7 @@ class CustomerRedemption(BaseNModel, DictModel):
85
85
  'redeemed_summary', 'redeemed_customer_acct', 'redeemed_outlet_details', 'redeemed_merchant_acct',
86
86
  'redeemed_datetime', 'is_revert', 'allow_to_revert', 'redeemed_outlet',
87
87
  'is_system_redemption', 'is_tier_program_redemption', 'tier_program_transaction_id',
88
- 'redeemed_by_username', 'reverted_datetime', 'reverted_by_username',
88
+ 'redeemed_by_username', 'reverted_datetime', 'reverted_by_username', 'prepaid_redeem_code',
89
89
  ]
90
90
 
91
91
  @staticmethod
@@ -100,6 +100,12 @@ class CustomerRedemption(BaseNModel, DictModel):
100
100
  def is_system_redemption(self):
101
101
  return self.is_tier_program_redemption
102
102
 
103
+ @property
104
+ def is_redeem_by_user(self):
105
+ if self.reward_format == program_conf.REWARD_FORMAT_PREPAID and is_not_empty(self.prepaid_redeem_code):
106
+ return True
107
+ return False
108
+
103
109
  @property
104
110
  def allow_to_revert(self):
105
111
  return self.is_revert == False and self.is_tier_program_redemption==False
@@ -128,6 +134,10 @@ class CustomerRedemption(BaseNModel, DictModel):
128
134
  def redeemed_merchant_acct(self):
129
135
  return MerchantAcct.fetch(self.merchant_acct.urlsafe())
130
136
 
137
+ @property
138
+ def redeemed_user_acct(self):
139
+ return User.fetch(self.user_acct.urlsafe())
140
+
131
141
  @property
132
142
  def redeemed_merchant_acct_key(self):
133
143
  return self.merchant_acct.urlsafe().decode('utf-8')
@@ -242,7 +252,7 @@ class CustomerRedemption(BaseNModel, DictModel):
242
252
  @staticmethod
243
253
  def create(customer, reward_format, redeemed_outlet=None, transaction_id=None,
244
254
  redeemed_amount=1, is_tier_program_redemption=False, tier_program_transaction_id=None,
245
- redeemed_voucher_keys_list=None, invoice_id=None, remarks=None,
255
+ redeemed_voucher_keys_list=None, invoice_id=None, remarks=None, prepaid_redeem_code=None,
246
256
  redeemed_by=None, redeemed_datetime=None, redemption_catalogue_transction_summary=None):
247
257
 
248
258
 
@@ -256,7 +266,7 @@ class CustomerRedemption(BaseNModel, DictModel):
256
266
  redeemed_by_username = redeemed_by.username
257
267
 
258
268
 
259
- redeem_transaction_id = transaction_id or generate_transaction_id(prefix='r')
269
+ redeem_transaction_id = transaction_id or generate_transaction_id(prefix='d')
260
270
 
261
271
  if redeemed_datetime is None:
262
272
  redeemed_datetime = datetime.utcnow()
@@ -552,7 +562,7 @@ class CustomerRedemption(BaseNModel, DictModel):
552
562
  reward_format = reward_format,
553
563
  redeemed_amount = redeemed_amount,
554
564
  redeemed_summary = redeemed_summary,
555
-
565
+ prepaid_redeem_code = prepaid_redeem_code,
556
566
  transaction_id = redeem_transaction_id,
557
567
  invoice_id = invoice_id,
558
568
  remarks = remarks,
@@ -13,6 +13,8 @@ IMAGE_BASE_URL = os.environ.get('IMAGE_BASE_URL')
13
13
  POS_PRODUCT = 'point_of_sales'
14
14
  LOYALTY_PRODUCT = 'loyalty'
15
15
 
16
+ PRODUCT_TYPES = (POS_PRODUCT, LOYALTY_PRODUCT)
17
+
16
18
  POS_PACKAGE_DEFAULT = 'lite'
17
19
  POS_PACKAGE_STANDARD = 'standard'
18
20
  POS_PACKAGE_SCALE = 'scale'
File without changes
File without changes
File without changes
File without changes