trex-model 1.4.5__tar.gz → 1.4.6__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 (61) hide show
  1. {trex-model-1.4.5 → trex-model-1.4.6}/PKG-INFO +1 -1
  2. {trex-model-1.4.5 → trex-model-1.4.6}/setup.py +1 -1
  3. {trex-model-1.4.5 → trex-model-1.4.6}/trex_model.egg-info/PKG-INFO +1 -1
  4. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/conf.py +8 -7
  5. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/marketing_models.py +244 -2
  6. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/merchant_models.py +49 -74
  7. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/message_model_helper.py +32 -19
  8. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/message_models.py +38 -4
  9. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/voucher_models.py +4 -1
  10. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/merchant_helpers.py +7 -1
  11. {trex-model-1.4.5 → trex-model-1.4.6}/LICENSE +0 -0
  12. {trex-model-1.4.5 → trex-model-1.4.6}/MANIFEST.in +0 -0
  13. {trex-model-1.4.5 → trex-model-1.4.6}/README.md +0 -0
  14. {trex-model-1.4.5 → trex-model-1.4.6}/setup.cfg +0 -0
  15. {trex-model-1.4.5 → trex-model-1.4.6}/trex_model.egg-info/SOURCES.txt +0 -0
  16. {trex-model-1.4.5 → trex-model-1.4.6}/trex_model.egg-info/dependency_links.txt +0 -0
  17. {trex-model-1.4.5 → trex-model-1.4.6}/trex_model.egg-info/requires.txt +0 -0
  18. {trex-model-1.4.5 → trex-model-1.4.6}/trex_model.egg-info/top_level.txt +0 -0
  19. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/__init__.py +0 -0
  20. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/__init__.py +0 -0
  21. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/__init__.py +0 -0
  22. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/admin_models.py +0 -0
  23. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/analytic_models.py +0 -0
  24. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/app_models.py +0 -0
  25. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/coporate_models.py +0 -0
  26. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/customer_model_helpers.py +0 -0
  27. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/customer_models.py +0 -0
  28. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/fb_subsriber_models.py +0 -0
  29. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/import_models.py +0 -0
  30. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/inventory_model.py +0 -0
  31. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/loyalty_models.py +0 -0
  32. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/lucky_draw_models.py +0 -0
  33. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/membership_models.py +0 -0
  34. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/model_decorators.py +0 -0
  35. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/ndb_models.py +0 -0
  36. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/pos_models.py +0 -0
  37. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/prepaid_models.py +0 -0
  38. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/product_models.py +0 -0
  39. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/program_models.py +0 -0
  40. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/rating_models.py +0 -0
  41. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/recruit_models.py +0 -0
  42. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/redeem_models.py +0 -0
  43. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/redemption_catalogue_models.py +0 -0
  44. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/referral_program_model.py +0 -0
  45. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/reward_model_helpers.py +0 -0
  46. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/reward_models.py +0 -0
  47. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/spending_base_program_model.py +0 -0
  48. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/system_models.py +0 -0
  49. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/task_models.py +0 -0
  50. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/test_models.py +0 -0
  51. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/transaction_models.py +0 -0
  52. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/datastore/user_models.py +0 -0
  53. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/model_decorator.py +0 -0
  54. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/models/prepaid_helpers.py +0 -0
  55. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/pos_conf.py +0 -0
  56. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/program_conf.py +0 -0
  57. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/utils/__init__.py +0 -0
  58. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/utils/gcloud/__init__.py +0 -0
  59. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/utils/gcloud/datastore_util.py +0 -0
  60. {trex-model-1.4.5 → trex-model-1.4.6}/trexmodel/utils/model/__init__.py +0 -0
  61. {trex-model-1.4.5 → trex-model-1.4.6}/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.4.5
3
+ Version: 1.4.6
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.4.5',
6
+ version='1.4.6',
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.4.5
3
+ Version: 1.4.6
4
4
  Summary: TRex database module package
5
5
  Home-page: https://bitbucket.org/lokjac/trex-model
6
6
  Author: Jack Lok
@@ -28,13 +28,14 @@ DATASTORE_CREDENTIAL_PATH = os.path.abspath(os.path.dirnam
28
28
 
29
29
  MERCHANT_STAT_FIGURE_UPDATE_INTERVAL_IN_MINUTES = os.environ.get('MERCHANT_STAT_FIGURE_UPDATE_INTERVAL_IN_MINUTES') or 60
30
30
 
31
- MESSAGE_CATEGORY_ANNOUNCEMENT = 'announcement'
32
- MESSAGE_CATEGORY_ALERT = 'alert'
33
- MESSAGE_CATEGORY_PROMOTION = 'promotion'
34
- MESSAGE_CATEGORY_SURVEY = 'survey'
35
- MESSAGE_CATEGORY_SYSTEM = 'system'
36
- MESSAGE_CATEGORY_REWARD = 'reward'
37
- MESSAGE_CATEGORY_REDEEM = 'redeem'
31
+ MESSAGE_CATEGORY_ANNOUNCEMENT = 'announcement'
32
+ MESSAGE_CATEGORY_ALERT = 'alert'
33
+ MESSAGE_CATEGORY_PROMOTION = 'promotion'
34
+ MESSAGE_CATEGORY_SURVEY = 'survey'
35
+ MESSAGE_CATEGORY_SYSTEM = 'system'
36
+ MESSAGE_CATEGORY_REWARD = 'reward'
37
+ MESSAGE_CATEGORY_REDEEM = 'redeem'
38
+ MESSAGE_CATEGORY_REDEMPTION_CATALOGUE = 'redemption_catalogue'
38
39
 
39
40
  MESSAGE_CATEGORIES = (MESSAGE_CATEGORY_ANNOUNCEMENT, MESSAGE_CATEGORY_ALERT, MESSAGE_CATEGORY_PROMOTION, MESSAGE_CATEGORY_SURVEY, MESSAGE_CATEGORY_SYSTEM, MESSAGE_CATEGORY_REWARD, MESSAGE_CATEGORY_REDEEM)
40
41
 
@@ -9,9 +9,11 @@ from trexmodel.models.datastore.merchant_models import MerchantUser,\
9
9
  MerchantAcct
10
10
  from trexlib.utils.string_util import is_not_empty, random_string
11
11
  from datetime import datetime
12
- from trexconf import conf
12
+ from trexconf import conf, program_conf
13
13
  import trexmodel.conf as model_conf
14
14
  import logging
15
+ from _datetime import timedelta
16
+ from trexconf.program_conf import MERCHANT_NEWS_STATUS_PUBLISH
15
17
 
16
18
  logger = logging.getLogger('model')
17
19
 
@@ -271,4 +273,244 @@ class ScheduledPushNotificationHistory(BaseNModel, DictModel):
271
273
  ndb.AND(
272
274
  ScheduledPushNotificationHistory.scheduled_datetime<=scheduled_datetime)).count(limit=conf.MAX_FETCH_RECORD)
273
275
 
274
-
276
+ class MerchantNewsFile(BaseNModel, DictModel):
277
+ '''
278
+ Merchant Account as ancestor
279
+ '''
280
+ label = ndb.StringProperty(required=True)
281
+ desc = ndb.StringProperty(required=False)
282
+ news_text = ndb.StringProperty(required=False)
283
+
284
+ news_file_type = ndb.StringProperty(required=False)
285
+ news_file_public_url = ndb.StringProperty(required=False)
286
+ news_file_storage_filename = ndb.StringProperty(required=False)
287
+
288
+ completed_status = ndb.StringProperty(required=True, choices=set(program_conf.MERCHANT_NEWS_STATUS))
289
+
290
+ start_date = ndb.DateProperty(required=True)
291
+ end_date = ndb.DateProperty(required=True)
292
+
293
+ enabled = ndb.BooleanProperty(default=True)
294
+
295
+ is_archived = ndb.BooleanProperty(default=False)
296
+
297
+ created_datetime = ndb.DateTimeProperty(required=True, auto_now_add=True)
298
+ modified_datetime = ndb.DateTimeProperty(required=False)
299
+ published_datetime = ndb.DateTimeProperty(required=False)
300
+ archived_datetime = ndb.DateTimeProperty(required=False)
301
+
302
+ created_by = ndb.KeyProperty(name="created_by", kind=MerchantUser)
303
+ created_by_username = ndb.StringProperty(required=False)
304
+
305
+ modified_by = ndb.KeyProperty(name="modified_by", kind=MerchantUser)
306
+ modified_by_username = ndb.StringProperty(required=False)
307
+
308
+ published_by = ndb.KeyProperty(name="published_by", kind=MerchantUser)
309
+ published_by_username = ndb.StringProperty(required=False)
310
+
311
+ archived_by = ndb.KeyProperty(name="archived_by", kind=MerchantUser)
312
+ archived_by_username = ndb.StringProperty(required=False)
313
+
314
+
315
+ dict_properties = ['image_url', 'completed_progress_in_percentage','is_published', 'is_enabled',
316
+ 'label', 'desc', 'news_text', 'start_date', 'end_date', 'enabled', 'is_archived',
317
+ 'completed_status']
318
+
319
+ @property
320
+ def merchant_acct(self):
321
+ return MerchantAcct.fetch(self.key.parent().urlsafe())
322
+
323
+ @property
324
+ def image_url(self):
325
+ if self.news_file_public_url:
326
+ return self.news_file_public_url
327
+ else:
328
+ return conf.MERCHANT_NEWS_DEFAULT_IMAGE
329
+
330
+ @property
331
+ def completed_progress_in_percentage(self):
332
+
333
+ return program_conf.merchant_news_completed_progress_percentage(self.completed_status)
334
+
335
+ @property
336
+ def is_published(self):
337
+ return self.completed_status == MERCHANT_NEWS_STATUS_PUBLISH
338
+
339
+ @property
340
+ def is_enabled(self):
341
+ return self.enabled
342
+
343
+ @staticmethod
344
+ def list_by_merchant_acct(merchant_acct):
345
+ result = MerchantNewsFile.query(ndb.AND(MerchantNewsFile.is_archived==False), ancestor=merchant_acct.create_ndb_key()).fetch(limit=conf.MAX_FETCH_RECORD)
346
+ return result
347
+
348
+ @staticmethod
349
+ def list_archived_by_merchant_acct(merchant_acct):
350
+ return MerchantNewsFile.query(ndb.AND(MerchantNewsFile.is_archived==True), ancestor=merchant_acct.create_ndb_key()).fetch(limit=model_conf.MAX_FETCH_RECORD)
351
+
352
+ @staticmethod
353
+ def create(merchant_acct, label=None, desc=None, news_text=None,
354
+ start_date=None, end_date=None, created_by=None):
355
+
356
+ created_by_username = None
357
+ if is_not_empty(created_by):
358
+ if isinstance(created_by, MerchantUser):
359
+ created_by_username = created_by.username
360
+
361
+ news_file = MerchantNewsFile(
362
+ parent = merchant_acct.create_ndb_key(),
363
+ label = label,
364
+ desc = desc,
365
+ news_text = news_text,
366
+ start_date = start_date,
367
+ end_date = end_date,
368
+ created_by = created_by.create_ndb_key(),
369
+ created_by_username = created_by_username,
370
+ created_datetime = datetime.utcnow(),
371
+ completed_status = program_conf.MERCHANT_NEWS_STATUS_BASE,
372
+ )
373
+
374
+ news_file.put()
375
+
376
+ return news_file
377
+
378
+ @staticmethod
379
+ def update(merchant_news, label=None, desc=None, news_text=None,
380
+ start_date=None, end_date=None, modified_by=None):
381
+
382
+ modified_by_username = None
383
+ if is_not_empty(modified_by):
384
+ if isinstance(modified_by, MerchantUser):
385
+ modified_by_username = modified_by.username
386
+
387
+ merchant_news.label = label
388
+ merchant_news.desc = desc
389
+ merchant_news.news_text = news_text
390
+ merchant_news.start_date = start_date
391
+ merchant_news.end_date = end_date
392
+ merchant_news.completed_status = program_conf.MERCHANT_NEWS_STATUS_BASE
393
+ merchant_news.modified_by = modified_by
394
+ merchant_news.modified_by_username = modified_by_username
395
+ merchant_news.modified_datetime = datetime.utcnow()
396
+
397
+
398
+ merchant_news.put()
399
+
400
+ @staticmethod
401
+ def upload_file(merchant_news, uploading_file, merchant_acct, bucket, news_file_type=None):
402
+ file_prefix = random_string(8)
403
+ news_file_storage_filename = 'merchant/'+merchant_acct.key_in_str+'/news/'+file_prefix+'-'+uploading_file.filename
404
+ blob = bucket.blob(news_file_storage_filename)
405
+
406
+ logger.debug('news_file_storage_filename=%s', news_file_storage_filename)
407
+
408
+ blob.upload_from_string(
409
+ uploading_file.read(),
410
+ content_type=uploading_file.content_type
411
+ )
412
+
413
+ uploaded_url = blob.public_url
414
+
415
+ logger.debug('uploaded_url=%s', uploaded_url)
416
+ logger.debug('news_file_type=%s', news_file_type)
417
+
418
+ if is_not_empty(merchant_news.news_file_storage_filename):
419
+ old_logo_blob = bucket.get_blob(merchant_news.news_file_storage_filename)
420
+ if old_logo_blob:
421
+ old_logo_blob.delete()
422
+
423
+
424
+ merchant_news.news_file_public_url = uploaded_url
425
+ merchant_news.news_file_storage_filename = news_file_storage_filename
426
+ merchant_news.news_file_type = news_file_type
427
+
428
+
429
+ merchant_news.put()
430
+
431
+ return merchant_news
432
+
433
+ @staticmethod
434
+ def update_news_material_uploaded(merchant_news, modified_by=None):
435
+
436
+ modified_by_username = None
437
+
438
+ if is_not_empty(modified_by):
439
+ if isinstance(modified_by, MerchantUser):
440
+ modified_by_username = modified_by.username
441
+
442
+ merchant_news.completed_status = program_conf.MERCHANT_NEWS_STATUS_UPLOAD_MATERIAL
443
+ merchant_news.modified_by = modified_by.create_ndb_key()
444
+ merchant_news.modified_by_username = modified_by_username
445
+ merchant_news.modified_datetime = datetime.utcnow()
446
+
447
+ merchant_news.put()
448
+
449
+ return merchant_news
450
+
451
+ @staticmethod
452
+ def remove_file(news_file, bucket):
453
+
454
+ old_logo_blob = bucket.get_blob(news_file.news_file_storage_filename)
455
+ if old_logo_blob:
456
+ old_logo_blob.delete()
457
+ news_file.delete()
458
+
459
+ def archived(self, archived_by=None):
460
+
461
+ archived_by_username = None
462
+ if is_not_empty(archived_by):
463
+ if isinstance(archived_by, MerchantUser):
464
+ archived_by_username = archived_by.username
465
+
466
+ self.is_archived = True
467
+ self.archived_datetime = datetime.utcnow()
468
+ self.archived_by = archived_by.create_ndb_key()
469
+ self.archived_by_username = archived_by_username
470
+ self.put()
471
+
472
+ merchant_acct = self.merchant_acct
473
+ merchant_acct.remove_merchant_news(self.key_in_str)
474
+
475
+ def to_configuration(self):
476
+ return {
477
+ 'merchant_news_key' : self.key_in_str,
478
+ 'image_url' : self.image_url,
479
+ 'label' : self.label,
480
+ 'content' : self.news_text,
481
+ 'start_datetime' : self.start_date.strftime('%d-%m-%Y %H:%M:%S'),
482
+ 'end_datetime' : self.end_date.strftime('%d-%m-%Y %H:%M:%S'),
483
+ }
484
+
485
+ def publish(self, published_by=None):
486
+
487
+ published_by_username = None
488
+ if is_not_empty(published_by):
489
+ if isinstance(published_by, MerchantUser):
490
+ published_by_username = published_by.username
491
+
492
+ self.completed_status = program_conf.MERCHANT_NEWS_STATUS_PUBLISH
493
+ self.published_by = published_by.create_ndb_key()
494
+ self.published_by_username = published_by_username
495
+ self.published_datetime = datetime.utcnow()
496
+ self.put()
497
+
498
+ merchant_acct = self.merchant_acct
499
+ merchant_acct.add_merchant_news(self.to_configuration())
500
+
501
+ @staticmethod
502
+ def disable_news(merchant_news):
503
+ merchant_news.enabled = False
504
+ merchant_news.put()
505
+
506
+ merchant_acct = merchant_news.merchant_acct
507
+ merchant_acct.remove_merchant_news(merchant_news.key_in_str)
508
+
509
+
510
+ @staticmethod
511
+ def enable_news(merchant_news):
512
+ merchant_news.enabled = True
513
+ merchant_news.put()
514
+
515
+ merchant_acct = merchant_news.merchant_acct
516
+ merchant_acct.add_merchant_news(merchant_news.to_configuration())
@@ -69,6 +69,7 @@ class MerchantAcct(MerchantMin):
69
69
  published_referral_program_configuration = ndb.JsonProperty()
70
70
  published_voucher_configuration = ndb.JsonProperty()
71
71
  published_redemption_catalogue_configuration = ndb.JsonProperty()
72
+ published_news_configuration = ndb.JsonProperty()
72
73
 
73
74
  membership_configuration = ndb.JsonProperty()
74
75
  tier_membership_configuration = ndb.JsonProperty()
@@ -91,11 +92,11 @@ class MerchantAcct(MerchantMin):
91
92
  'registered_datetime', 'modified_datetime', 'plan_start_date', 'plan_end_date', 'currency_code',
92
93
  'timezone', 'effective_referral_program_count',
93
94
  'published_program_configuration', 'published_referral_program_configuration',
94
- 'published_voucher_configuration', 'membership_configuration',
95
+ 'published_voucher_configuration', 'published_news_configuration', 'membership_configuration',
95
96
  'tier_membership_configuration', 'prepaid_configuration', 'lucky_draw_configuration', 'product_modifier_configuration',
96
97
  'dashboard_stat_figure', 'program_settings', 'is_tier_membership_configured', 'website',
97
98
  'product_package', 'loyalty_package','account_plan','outlet_count', 'outlet_limit',
98
- 'published_redemption_catalogue_configuration',
99
+ 'published_redemption_catalogue_configuration','logo_public_url'
99
100
  ]
100
101
 
101
102
 
@@ -636,7 +637,51 @@ class MerchantAcct(MerchantMin):
636
637
  self.published_voucher_configuration['vouchers'] = new_vouchers_list
637
638
  self.published_voucher_configuration['count'] = len(new_vouchers_list)
638
639
 
639
- self.put()
640
+ self.put()
641
+
642
+ def add_merchant_news(self, merchant_news_configuration):
643
+ if is_empty(self.published_news_configuration):
644
+ self.published_news_configuration = {
645
+ 'news' :[merchant_news_configuration],
646
+ 'count' : 1,
647
+ }
648
+
649
+ else:
650
+ existing_merchant_news_list = self.published_news_configuration.get('news')
651
+
652
+ merchant_news_key = merchant_news_configuration.get('merchant_news_key')
653
+
654
+ if len(existing_merchant_news_list)>0:
655
+ index = 0
656
+ for v in existing_merchant_news_list:
657
+ if v.get('merchant_news_key') == merchant_news_key:
658
+ existing_merchant_news_list.pop(index)
659
+
660
+ index = index+1
661
+
662
+ existing_merchant_news_list.append(merchant_news_configuration)
663
+
664
+ self.published_news_configuration['news'] = existing_merchant_news_list
665
+ self.published_news_configuration['count'] = len(existing_merchant_news_list)
666
+
667
+ self.put()
668
+
669
+ def remove_merchant_news(self, merchant_news_key):
670
+ existing_merchant_news_list = self.published_news_configuration['news']
671
+
672
+ latest_news_list = []
673
+ #now = datetime.now()
674
+ for merchant_news in existing_merchant_news_list:
675
+ if merchant_news.get('merchant_news_key') != merchant_news_key:
676
+ #end_datetime = datetime.strptime('%d-%m-%Y %H:%m:%S', merchant_news.ge('end_datetime'))
677
+ #if end_datetime >
678
+ latest_news_list.append(merchant_news)
679
+
680
+
681
+ self.published_news_configuration['news'] = latest_news_list
682
+ self.published_news_configuration['count'] = len(latest_news_list)
683
+
684
+ self.put()
640
685
 
641
686
  def update_prepaid_program(self, prepaid_configuration):
642
687
  if self.prepaid_configuration is None or len(self.prepaid_configuration)==0:
@@ -1895,74 +1940,4 @@ class BannerFile(BaseNModel, DictModel):
1895
1940
  old_logo_blob.delete()
1896
1941
  banner_file.delete()
1897
1942
 
1898
- class MerchantNewsFile(BaseNModel, DictModel):
1899
- '''
1900
- Merchant Account as ancestor
1901
- '''
1902
- label = ndb.StringProperty(required=False)
1903
- desc = ndb.StringProperty(required=False)
1904
- news_text = ndb.StringProperty(required=False)
1905
-
1906
- news_file_type = ndb.StringProperty(required=True)
1907
- news_file_public_url = ndb.StringProperty(required=True)
1908
- news_file_storage_filename = ndb.StringProperty(required=True)
1909
- start_date = ndb.DateProperty(required=True)
1910
- end_date = ndb.DateProperty(required=True)
1911
-
1912
-
1913
- dict_properties = ['news_file_public_url', 'news_file_storage_filename', 'news_file_type', 'label', 'desc', 'news_text', 'start_date', 'end_date']
1914
-
1915
- @staticmethod
1916
- def list_by_merchant_acct(merchant_acct):
1917
- result = MerchantNewsFile.query(ancestor=merchant_acct.create_ndb_key()).fetch(limit=conf.MAX_FETCH_RECORD)
1918
- return result
1919
-
1920
- @staticmethod
1921
- def create(merchant_acct, label=None, desc=None, news_text=None):
1922
- news_file = MerchantNewsFile(
1923
- parent = merchant_acct.create_ndb_key(),
1924
- label = label,
1925
- desc = desc,
1926
- news_text = news_text,
1927
- )
1928
-
1929
- news_file.put()
1930
-
1931
- @staticmethod
1932
- def upload_file(merchant_news, uploading_file, merchant_acct, bucket, news_file_type=None):
1933
- file_prefix = random_string(8)
1934
- news_file_storage_filename = 'merchant/'+merchant_acct.key_in_str+'/news/'+file_prefix+'-'+uploading_file.filename
1935
- blob = bucket.blob(news_file_storage_filename)
1936
-
1937
- logger.debug('news_file_storage_filename=%s', news_file_storage_filename)
1938
-
1939
- blob.upload_from_string(
1940
- uploading_file.read(),
1941
- content_type=uploading_file.content_type
1942
- )
1943
-
1944
- uploaded_url = blob.public_url
1945
-
1946
- logger.debug('uploaded_url=%s', uploaded_url)
1947
- logger.debug('news_file_type=%s', news_file_type)
1948
-
1949
- if is_not_empty(merchant_news.news_file_storage_filename):
1950
- old_logo_blob = bucket.get_blob(merchant_news.news_file_storage_filename)
1951
- if old_logo_blob:
1952
- old_logo_blob.delete()
1953
-
1954
-
1955
- merchant_news.news_file_public_url = uploaded_url
1956
- merchant_news.news_file_storage_filename = news_file_storage_filename
1957
- merchant_news.news_file_type = news_file_type
1958
-
1959
-
1960
- merchant_news.put()
1961
-
1962
- @staticmethod
1963
- def remove_file(news_file, bucket):
1964
-
1965
- old_logo_blob = bucket.get_blob(news_file.news_file_storage_filename)
1966
- if old_logo_blob:
1967
- old_logo_blob.delete()
1968
- news_file.delete()
1943
+
@@ -6,7 +6,7 @@ Created on 9 Nov 2023
6
6
  from trexmodel.program_conf import REWARD_FORMAT_MAP, REWARD_FORMAT_PREPAID
7
7
  from trexmodel.models.datastore.message_models import Message
8
8
  from trexmodel.conf import MESSAGE_CATEGORY_REWARD, MESSAGE_STATUS_NEW,\
9
- MESSAGE_CATEGORY_REDEEM
9
+ MESSAGE_CATEGORY_REDEEM, MESSAGE_CATEGORY_REDEMPTION_CATALOGUE
10
10
  from trexconf import program_conf
11
11
  from babel.numbers import format_currency
12
12
  import logging
@@ -140,23 +140,26 @@ message_logo_image_template = '''
140
140
 
141
141
 
142
142
  def create_transaction_message(customer_transaction):
143
- user_acct = customer_transaction.transact_user_acct
144
- source_key = customer_transaction.key_in_str
143
+ user_acct = customer_transaction.transact_user_acct
144
+ source_key = customer_transaction.key_in_str
145
+ customer = customer_transaction.transact_customer_acct
146
+ merchant_acct = customer.registered_merchant_acct
145
147
  message = Message.get_by_source_key(source_key)
146
148
 
147
149
  if message is None:
148
150
  message = Message(
151
+ parent = user_acct.create_ndb_key(),
149
152
  message_to = user_acct.create_ndb_key(),
150
153
  title = 'Transaction Reward',
151
154
  message_category = MESSAGE_CATEGORY_REWARD,
152
155
  message_content = __create_entiled_message_from_customer_transaction(customer_transaction),
153
156
  message_data = __create_message_data_from_transaction(customer_transaction),
154
157
  status = MESSAGE_STATUS_NEW,
155
-
158
+ message_from = merchant_acct.brand_name,
156
159
  )
157
160
  message.put()
158
- user_acct.new_message_count+=1
159
- user_acct.put()
161
+ #user_acct.new_message_count+=1
162
+ #user_acct.put()
160
163
 
161
164
  return message
162
165
 
@@ -168,46 +171,50 @@ def create_redemption_message(customer_redemption):
168
171
 
169
172
  if message is None:
170
173
  message = Message(
174
+ parent = user_acct.create_ndb_key(),
171
175
  source_key = source_key,
172
176
  message_to = user_acct.create_ndb_key(),
173
177
  title = 'Redemption',
174
178
  message_category = MESSAGE_CATEGORY_REDEEM,
175
179
  message_content = __create_message_from_redeem_transaction(merchant_acct, customer_redemption),
176
- message_data = __create_message_data_from_transaction(customer_redemption),
180
+ message_data = __create_message_data_from_redemption(customer_redemption),
177
181
  status = MESSAGE_STATUS_NEW,
178
-
182
+ message_from = merchant_acct.brand_name,
179
183
  )
180
184
  message.put()
181
- user_acct.new_message_count+=1
182
- user_acct.put()
185
+ #user_acct.new_message_count+=1
186
+ #user_acct.put()
183
187
 
184
188
  return message
189
+
185
190
 
186
191
  def create_redeem_catalogue_item_message(customer, entitled_vouchers_summary, redemption_catalogue_transaction):
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)
192
+ user_acct = customer.registered_user_acct
193
+ merchant_acct = customer.registered_merchant_acct
194
+ source_key = redemption_catalogue_transaction.key_in_str
195
+ message = Message.get_by_source_key(source_key)
190
196
 
191
197
  if message is None:
192
198
  message = Message(
193
-
199
+ parent = user_acct.create_ndb_key(),
194
200
  message_to = user_acct.create_ndb_key(),
195
201
  title = 'Redemption Catalogue Reward',
196
- message_category = MESSAGE_CATEGORY_REWARD,
202
+ message_category = MESSAGE_CATEGORY_REDEMPTION_CATALOGUE,
197
203
  message_content = __create_message_from_redeem_catalogue_transaction(customer, entitled_vouchers_summary),
198
204
  message_data = __create_message_data_from_redemption_catalogue(redemption_catalogue_transaction),
199
205
  status = MESSAGE_STATUS_NEW,
206
+ message_from = merchant_acct.brand_name,
200
207
 
201
208
  )
202
209
  message.put()
203
- user_acct.new_message_count+=1
204
- user_acct.put()
210
+ #user_acct.new_message_count+=1
211
+ #user_acct.put()
205
212
 
206
213
  return message
207
214
 
208
215
  def __create_message_data_from_transaction(customer_transaction):
209
216
  return {
210
- 'transaction_key' : customer_transaction.key_in_str,
217
+ 'reward_transaction_key' : customer_transaction.key_in_str,
211
218
 
212
219
  }
213
220
 
@@ -215,7 +222,13 @@ def __create_message_data_from_redemption_catalogue(redemption_catalogue_transac
215
222
  return {
216
223
  'redemption_catalogue_transaction_key' : redemption_catalogue_transaction.key_in_str,
217
224
 
218
- }
225
+ }
226
+
227
+ def __create_message_data_from_redemption(redemption_transaction):
228
+ return {
229
+ 'redemption_transaction_key' : redemption_transaction.key_in_str,
230
+
231
+ }
219
232
 
220
233
  def __create_entiled_message_from_customer_transaction(customer_transaction):
221
234
 
@@ -13,6 +13,9 @@ from trexmodel import conf
13
13
  from trexmodel.conf import MESSAGE_STATUS_SET, MESSAGE_STATUS_NEW, MESSAGE_CATEGORY_SYSTEM,\
14
14
  MESSAGE_STATUS_READ, MESSAGE_CATEGORIES, MESSAGE_CATEGORY_ANNOUNCEMENT
15
15
  from trexmodel.models.datastore.transaction_models import CustomerTransaction
16
+ from trexmodel.models.datastore.redeem_models import RedemptionCatalogueTransaction,\
17
+ CustomerRedemption
18
+ from trexmodel.models.datastore.customer_models import Customer
16
19
 
17
20
 
18
21
  logger = logging.getLogger('model')
@@ -29,12 +32,16 @@ content_body=[text in html]
29
32
  '''
30
33
 
31
34
  class Message(BaseNModel, DictModel):
35
+ '''
36
+ User as ancestor
37
+ '''
32
38
  message_to = ndb.KeyProperty(name="message_to", kind=User)
33
39
  source_key = ndb.StringProperty(required=False)
34
40
  title = ndb.StringProperty(required=True)
35
41
  message_category = ndb.StringProperty(required=True, default=MESSAGE_CATEGORY_SYSTEM, choices=MESSAGE_CATEGORIES)
36
42
  message_content = ndb.JsonProperty(required=True, indexed=False)
37
43
  message_data = ndb.JsonProperty(required=True, indexed=False)
44
+ message_from = ndb.StringProperty(required=False)
38
45
  status = ndb.StringProperty(required=True, default=MESSAGE_STATUS_NEW, choices=MESSAGE_STATUS_SET)
39
46
  created_datetime = ndb.DateTimeProperty(required=True, auto_now_add=True)
40
47
  read_datetime = ndb.DateTimeProperty(required=False)
@@ -51,13 +58,27 @@ class Message(BaseNModel, DictModel):
51
58
 
52
59
  @property
53
60
  def customer_transaction_entity(self):
54
- customer_transaction_key = self.message_data.get('transaction_key')
61
+ customer_transaction_key = self.message_data.get('reward_transaction_key')
55
62
  if customer_transaction_key:
56
- return CustomerTransaction.fetch(customer_transaction_key)
63
+ return CustomerTransaction.fetch(customer_transaction_key)
64
+
65
+ @property
66
+ def customer_redemption_catalogue_entity(self):
67
+ customer_redemption_key = self.message_data.get('redemption_catalogue_transaction_key')
68
+ if customer_redemption_key:
69
+ return RedemptionCatalogueTransaction.fetch(customer_redemption_key)
70
+
71
+ @property
72
+ def customer_redemption_entity(self):
73
+ customer_redemption_key = self.message_data.get('redemption_transaction_key')
74
+ if customer_redemption_key:
75
+ return CustomerRedemption.fetch(customer_redemption_key)
76
+
57
77
 
58
78
  @staticmethod
59
- def create(source_key=None, message_to=None, title=None, message_type=MESSAGE_CATEGORY_ANNOUNCEMENT,message_content={}):
79
+ def create(user_acct, source_key=None, message_to=None, title=None, message_type=MESSAGE_CATEGORY_ANNOUNCEMENT,message_content={}):
60
80
  Message(
81
+ parent = user_acct.create_ndb_key(),
61
82
  source_key = source_key,
62
83
  message_to = message_to.create_ndb_key(),
63
84
  title = title,
@@ -75,12 +96,13 @@ class Message(BaseNModel, DictModel):
75
96
  message.status = MESSAGE_STATUS_READ
76
97
  message.read_datetime = datetime.utcnow()
77
98
  message.put()
78
-
99
+ '''
79
100
  user_acct.new_message_count-=1
80
101
  if user_acct.new_message_count<0:
81
102
  user_acct.new_message_count=0
82
103
 
83
104
  user_acct.put()
105
+ '''
84
106
 
85
107
  @staticmethod
86
108
  def update_delete(message_key):
@@ -92,10 +114,22 @@ class Message(BaseNModel, DictModel):
92
114
 
93
115
  @staticmethod
94
116
  def list_paginated_by_user_account(user_acct, limit=conf.MAX_FETCH_RECORD, start_cursor=None):
117
+ #query = Message.query(ancestor=user_acct.create_ndb_key()).order(-Message.created_datetime)
95
118
  query = Message.query(ndb.AND(Message.message_to==user_acct.create_ndb_key())).order(-Message.created_datetime)
96
119
 
97
120
  return Message.list_all_with_condition_query(query, limit=limit, start_cursor=start_cursor, return_with_cursor=True, keys_only=False)
98
121
 
122
+
123
+ @staticmethod
124
+ def count_new_message(user_acct):
125
+ return Message.count_by_status(user_acct, status=conf.MESSAGE_STATUS_NEW)
126
+
127
+ @staticmethod
128
+ def count_by_status(user_acct, status=conf.MESSAGE_STATUS_NEW):
129
+ query = Message.query(ndb.AND(Message.status==status), ancestor=user_acct.create_ndb_key()).order(-Message.created_datetime)
130
+
131
+ return Message.count_with_condition_query(query, limit=conf.MAX_FETCH_RECORD)
132
+
99
133
 
100
134
  @staticmethod
101
135
  def get_by_source_key(source_key):
@@ -258,10 +258,13 @@ class MerchantVoucher(VoucherBase):
258
258
  merchant_voucher.terms_and_conditions = terms_and_conditions
259
259
  merchant_voucher.redeem_limit_type = redeem_limit_type
260
260
  merchant_voucher.redeem_limit_count = redeem_limit_count
261
- merchant_voucher.completed_status = program_conf.VOUCHER_STATUS_BASE
261
+
262
262
  merchant_voucher.modified_by = modified_by.create_ndb_key()
263
263
  merchant_voucher.modified_by_username = modified_by_username
264
264
 
265
+ if merchant_voucher.completed_status!=program_conf.VOUCHER_STATUS_BASE:
266
+ merchant_voucher.completed_status = program_conf.VOUCHER_STATUS_PUBLISH
267
+
265
268
  merchant_voucher.put()
266
269
 
267
270
  return merchant_voucher
@@ -36,6 +36,8 @@ def construct_merchant_acct_info(merchant_acct):
36
36
  referral_program_settings = merchant_acct.program_settings.get('referral_program', {})
37
37
 
38
38
 
39
+
40
+ '''
39
41
  merchant_news_list = [
40
42
  {
41
43
  'image_url': 'https://scontent.cdninstagram.com/v/t39.30808-6/395358935_817823987014226_84933362912055577_n.jpg?stp=dst-jpg_e35&efg=eyJ2ZW5jb2RlX3RhZyI6ImltYWdlX3VybGdlbi42NTF4NjUwLnNkci5mMzA4MDgifQ&_nc_ht=scontent.cdninstagram.com&_nc_cat=102&_nc_ohc=v_kSSi1t6JgQ7kNvgERj6Vi&edm=APs17CUAAAAA&ccb=7-5&ig_cache_key=MzIyMjUxMzQ0MzI0ODIyMzYzMg%3D%3D.2-ccb7-5&oh=00_AfAUoP1jFeskadyDc4xrwkZb1PuH9t5JSajL6Q5tKAwCew&oe=663DAE72&_nc_sid=10d13b',
@@ -51,8 +53,12 @@ def construct_merchant_acct_info(merchant_acct):
51
53
  }
52
54
 
53
55
  ]
54
-
56
+ '''
55
57
  merchant_news_list=[]
58
+
59
+ if merchant_acct.published_news_configuration:
60
+ merchant_news_list = merchant_acct.published_news_configuration['news']
61
+
56
62
  info = {
57
63
  'key' : merchant_acct.key_in_str,
58
64
  'company_name' : merchant_acct.company_name,
File without changes
File without changes
File without changes
File without changes