trex-model 1.4.5__tar.gz → 1.5.0__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.5.0}/PKG-INFO +1 -1
  2. {trex-model-1.4.5 → trex-model-1.5.0}/setup.py +1 -1
  3. {trex-model-1.4.5 → trex-model-1.5.0}/trex_model.egg-info/PKG-INFO +1 -1
  4. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/conf.py +19 -9
  5. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/marketing_models.py +244 -2
  6. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/merchant_models.py +120 -75
  7. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/message_model_helper.py +34 -20
  8. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/message_models.py +38 -4
  9. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/program_models.py +100 -7
  10. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/voucher_models.py +4 -1
  11. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/merchant_helpers.py +7 -1
  12. {trex-model-1.4.5 → trex-model-1.5.0}/LICENSE +0 -0
  13. {trex-model-1.4.5 → trex-model-1.5.0}/MANIFEST.in +0 -0
  14. {trex-model-1.4.5 → trex-model-1.5.0}/README.md +0 -0
  15. {trex-model-1.4.5 → trex-model-1.5.0}/setup.cfg +0 -0
  16. {trex-model-1.4.5 → trex-model-1.5.0}/trex_model.egg-info/SOURCES.txt +0 -0
  17. {trex-model-1.4.5 → trex-model-1.5.0}/trex_model.egg-info/dependency_links.txt +0 -0
  18. {trex-model-1.4.5 → trex-model-1.5.0}/trex_model.egg-info/requires.txt +0 -0
  19. {trex-model-1.4.5 → trex-model-1.5.0}/trex_model.egg-info/top_level.txt +0 -0
  20. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/__init__.py +0 -0
  21. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/__init__.py +0 -0
  22. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/__init__.py +0 -0
  23. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/admin_models.py +0 -0
  24. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/analytic_models.py +0 -0
  25. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/app_models.py +0 -0
  26. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/coporate_models.py +0 -0
  27. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/customer_model_helpers.py +0 -0
  28. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/customer_models.py +0 -0
  29. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/fb_subsriber_models.py +0 -0
  30. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/import_models.py +0 -0
  31. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/inventory_model.py +0 -0
  32. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/loyalty_models.py +0 -0
  33. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/lucky_draw_models.py +0 -0
  34. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/membership_models.py +0 -0
  35. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/model_decorators.py +0 -0
  36. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/ndb_models.py +0 -0
  37. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/pos_models.py +0 -0
  38. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/prepaid_models.py +0 -0
  39. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/product_models.py +0 -0
  40. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/rating_models.py +0 -0
  41. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/recruit_models.py +0 -0
  42. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/redeem_models.py +0 -0
  43. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/redemption_catalogue_models.py +0 -0
  44. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/referral_program_model.py +0 -0
  45. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/reward_model_helpers.py +0 -0
  46. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/reward_models.py +0 -0
  47. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/spending_base_program_model.py +0 -0
  48. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/system_models.py +0 -0
  49. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/task_models.py +0 -0
  50. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/test_models.py +0 -0
  51. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/transaction_models.py +0 -0
  52. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/datastore/user_models.py +0 -0
  53. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/model_decorator.py +0 -0
  54. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/models/prepaid_helpers.py +0 -0
  55. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/pos_conf.py +0 -0
  56. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/program_conf.py +0 -0
  57. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/utils/__init__.py +0 -0
  58. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/utils/gcloud/__init__.py +0 -0
  59. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/utils/gcloud/datastore_util.py +0 -0
  60. {trex-model-1.4.5 → trex-model-1.5.0}/trexmodel/utils/model/__init__.py +0 -0
  61. {trex-model-1.4.5 → trex-model-1.5.0}/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.5.0
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.5.0',
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.5.0
4
4
  Summary: TRex database module package
5
5
  Home-page: https://bitbucket.org/lokjac/trex-model
6
6
  Author: Jack Lok
@@ -28,15 +28,25 @@ 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'
38
-
39
- MESSAGE_CATEGORIES = (MESSAGE_CATEGORY_ANNOUNCEMENT, MESSAGE_CATEGORY_ALERT, MESSAGE_CATEGORY_PROMOTION, MESSAGE_CATEGORY_SURVEY, MESSAGE_CATEGORY_SYSTEM, MESSAGE_CATEGORY_REWARD, MESSAGE_CATEGORY_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'
39
+
40
+ MESSAGE_CATEGORIES = (
41
+ MESSAGE_CATEGORY_ANNOUNCEMENT,
42
+ MESSAGE_CATEGORY_ALERT,
43
+ MESSAGE_CATEGORY_PROMOTION,
44
+ MESSAGE_CATEGORY_SURVEY,
45
+ MESSAGE_CATEGORY_SYSTEM,
46
+ MESSAGE_CATEGORY_REWARD,
47
+ MESSAGE_CATEGORY_REDEEM,
48
+ MESSAGE_CATEGORY_REDEMPTION_CATALOGUE,
49
+ )
40
50
 
41
51
  MESSAGE_STATUS_NEW = 'n'
42
52
  MESSAGE_STATUS_READ = 'r'
@@ -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,8 @@ 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()
73
+ published_tier_program_configuration = ndb.JsonProperty()
72
74
 
73
75
  membership_configuration = ndb.JsonProperty()
74
76
  tier_membership_configuration = ndb.JsonProperty()
@@ -90,12 +92,12 @@ class MerchantAcct(MerchantMin):
90
92
  'office_phone', 'fax_phone', 'email', 'account_code', 'country',
91
93
  'registered_datetime', 'modified_datetime', 'plan_start_date', 'plan_end_date', 'currency_code',
92
94
  'timezone', 'effective_referral_program_count',
93
- 'published_program_configuration', 'published_referral_program_configuration',
94
- 'published_voucher_configuration', 'membership_configuration',
95
+ 'published_program_configuration', 'published_tier_program_configuration', 'published_referral_program_configuration',
96
+ 'published_voucher_configuration', 'published_news_configuration', 'membership_configuration',
95
97
  'tier_membership_configuration', 'prepaid_configuration', 'lucky_draw_configuration', 'product_modifier_configuration',
96
98
  'dashboard_stat_figure', 'program_settings', 'is_tier_membership_configured', 'website',
97
99
  'product_package', 'loyalty_package','account_plan','outlet_count', 'outlet_limit',
98
- 'published_redemption_catalogue_configuration',
100
+ 'published_redemption_catalogue_configuration','logo_public_url'
99
101
  ]
100
102
 
101
103
 
@@ -572,6 +574,32 @@ class MerchantAcct(MerchantMin):
572
574
 
573
575
  self.put()
574
576
 
577
+ def update_published_tier_program(self, program_configuration):
578
+ if is_empty(self.published_tier_program_configuration):
579
+ self.published_program_configuration = {
580
+ 'programs' :[program_configuration],
581
+ 'count' : 1,
582
+ }
583
+
584
+ else:
585
+ self.flush_dirty_program_configuration()
586
+ existing_programs_list = self.published_tier_program_configuration.get('programs')
587
+
588
+ program_key = program_configuration.get('program_key')
589
+ index = 0
590
+ for p in existing_programs_list:
591
+ if p.get('program_key') == program_key:
592
+ existing_programs_list.pop(index)
593
+
594
+ index = index+1
595
+
596
+ existing_programs_list.append(program_configuration)
597
+
598
+ self.published_tier_program_configuration['programs'] = existing_programs_list
599
+ self.published_tier_program_configuration['count'] = len(existing_programs_list)
600
+
601
+ self.put()
602
+
575
603
  def update_published_referral_program(self, program_configuration):
576
604
  if is_empty(self.published_referral_program_configuration):
577
605
  self.published_referral_program_configuration = {
@@ -636,7 +664,51 @@ class MerchantAcct(MerchantMin):
636
664
  self.published_voucher_configuration['vouchers'] = new_vouchers_list
637
665
  self.published_voucher_configuration['count'] = len(new_vouchers_list)
638
666
 
639
- self.put()
667
+ self.put()
668
+
669
+ def add_merchant_news(self, merchant_news_configuration):
670
+ if is_empty(self.published_news_configuration):
671
+ self.published_news_configuration = {
672
+ 'news' :[merchant_news_configuration],
673
+ 'count' : 1,
674
+ }
675
+
676
+ else:
677
+ existing_merchant_news_list = self.published_news_configuration.get('news')
678
+
679
+ merchant_news_key = merchant_news_configuration.get('merchant_news_key')
680
+
681
+ if len(existing_merchant_news_list)>0:
682
+ index = 0
683
+ for v in existing_merchant_news_list:
684
+ if v.get('merchant_news_key') == merchant_news_key:
685
+ existing_merchant_news_list.pop(index)
686
+
687
+ index = index+1
688
+
689
+ existing_merchant_news_list.append(merchant_news_configuration)
690
+
691
+ self.published_news_configuration['news'] = existing_merchant_news_list
692
+ self.published_news_configuration['count'] = len(existing_merchant_news_list)
693
+
694
+ self.put()
695
+
696
+ def remove_merchant_news(self, merchant_news_key):
697
+ existing_merchant_news_list = self.published_news_configuration['news']
698
+
699
+ latest_news_list = []
700
+ #now = datetime.now()
701
+ for merchant_news in existing_merchant_news_list:
702
+ if merchant_news.get('merchant_news_key') != merchant_news_key:
703
+ #end_datetime = datetime.strptime('%d-%m-%Y %H:%m:%S', merchant_news.ge('end_datetime'))
704
+ #if end_datetime >
705
+ latest_news_list.append(merchant_news)
706
+
707
+
708
+ self.published_news_configuration['news'] = latest_news_list
709
+ self.published_news_configuration['count'] = len(latest_news_list)
710
+
711
+ self.put()
640
712
 
641
713
  def update_prepaid_program(self, prepaid_configuration):
642
714
  if self.prepaid_configuration is None or len(self.prepaid_configuration)==0:
@@ -867,6 +939,49 @@ class MerchantAcct(MerchantMin):
867
939
  self.published_program_configuration['count'] = program_count
868
940
 
869
941
  self.put()
942
+
943
+ def remove_tier_program_from_published_tier_program_configuration(self, program_key_to_remove):
944
+
945
+ logger.debug('remove_tier_program_from_published_tier_program_configuration: program_key_to_remove=%s', program_key_to_remove)
946
+
947
+ #self.flush_dirty_program_configuration()
948
+ if self.published_tier_program_configuration:
949
+ existing_programs_list = self.published_tier_program_configuration['programs']
950
+ program_count = len(existing_programs_list)
951
+
952
+ else:
953
+ self.published_tier_program_configuration = {}
954
+ existing_programs_list = []
955
+ program_count = 0
956
+
957
+
958
+ logger.debug('program_count before remove=%s', program_count)
959
+
960
+ index = 0
961
+
962
+ for program in existing_programs_list:
963
+
964
+ logger.debug('program_key=%s', program.get('program_key'))
965
+
966
+ is_same_program_key = program.get('program_key') == program_key_to_remove
967
+
968
+ logger.debug('is_same_program_key=%s', is_same_program_key)
969
+
970
+ if is_same_program_key:
971
+ existing_programs_list.pop(index)
972
+
973
+ logger.debug('Found program to be remove')
974
+
975
+ index = index+1
976
+
977
+ program_count = len(existing_programs_list)
978
+
979
+ logger.debug('program_count after remove=%s', program_count)
980
+
981
+ self.published_tier_program_configuration['programs'] = existing_programs_list
982
+ self.published_tier_program_configuration['count'] = program_count
983
+
984
+ self.put()
870
985
 
871
986
  def remove_program_from_published_referral_program_configuration(self, program_key_to_remove):
872
987
 
@@ -1895,74 +2010,4 @@ class BannerFile(BaseNModel, DictModel):
1895
2010
  old_logo_blob.delete()
1896
2011
  banner_file.delete()
1897
2012
 
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()
2013
+
@@ -6,10 +6,11 @@ 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
13
+ from flask_babel import gettext
13
14
 
14
15
 
15
16
  logger = logging.getLogger('helper')
@@ -140,23 +141,26 @@ message_logo_image_template = '''
140
141
 
141
142
 
142
143
  def create_transaction_message(customer_transaction):
143
- user_acct = customer_transaction.transact_user_acct
144
- source_key = customer_transaction.key_in_str
144
+ user_acct = customer_transaction.transact_user_acct
145
+ source_key = customer_transaction.key_in_str
146
+ customer = customer_transaction.transact_customer_acct
147
+ merchant_acct = customer.registered_merchant_acct
145
148
  message = Message.get_by_source_key(source_key)
146
149
 
147
150
  if message is None:
148
151
  message = Message(
152
+ parent = user_acct.create_ndb_key(),
149
153
  message_to = user_acct.create_ndb_key(),
150
154
  title = 'Transaction Reward',
151
155
  message_category = MESSAGE_CATEGORY_REWARD,
152
156
  message_content = __create_entiled_message_from_customer_transaction(customer_transaction),
153
157
  message_data = __create_message_data_from_transaction(customer_transaction),
154
158
  status = MESSAGE_STATUS_NEW,
155
-
159
+ message_from = merchant_acct.brand_name,
156
160
  )
157
161
  message.put()
158
- user_acct.new_message_count+=1
159
- user_acct.put()
162
+ #user_acct.new_message_count+=1
163
+ #user_acct.put()
160
164
 
161
165
  return message
162
166
 
@@ -168,46 +172,50 @@ def create_redemption_message(customer_redemption):
168
172
 
169
173
  if message is None:
170
174
  message = Message(
175
+ parent = user_acct.create_ndb_key(),
171
176
  source_key = source_key,
172
177
  message_to = user_acct.create_ndb_key(),
173
178
  title = 'Redemption',
174
179
  message_category = MESSAGE_CATEGORY_REDEEM,
175
180
  message_content = __create_message_from_redeem_transaction(merchant_acct, customer_redemption),
176
- message_data = __create_message_data_from_transaction(customer_redemption),
181
+ message_data = __create_message_data_from_redemption(customer_redemption),
177
182
  status = MESSAGE_STATUS_NEW,
178
-
183
+ message_from = merchant_acct.brand_name,
179
184
  )
180
185
  message.put()
181
- user_acct.new_message_count+=1
182
- user_acct.put()
186
+ #user_acct.new_message_count+=1
187
+ #user_acct.put()
183
188
 
184
189
  return message
190
+
185
191
 
186
192
  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)
193
+ user_acct = customer.registered_user_acct
194
+ merchant_acct = customer.registered_merchant_acct
195
+ source_key = redemption_catalogue_transaction.key_in_str
196
+ message = Message.get_by_source_key(source_key)
190
197
 
191
198
  if message is None:
192
199
  message = Message(
193
-
200
+ parent = user_acct.create_ndb_key(),
194
201
  message_to = user_acct.create_ndb_key(),
195
- title = 'Redemption Catalogue Reward',
196
- message_category = MESSAGE_CATEGORY_REWARD,
202
+ title = gettext('Redemption Catalogue Reward'),
203
+ message_category = MESSAGE_CATEGORY_REDEMPTION_CATALOGUE,
197
204
  message_content = __create_message_from_redeem_catalogue_transaction(customer, entitled_vouchers_summary),
198
205
  message_data = __create_message_data_from_redemption_catalogue(redemption_catalogue_transaction),
199
206
  status = MESSAGE_STATUS_NEW,
207
+ message_from = merchant_acct.brand_name,
200
208
 
201
209
  )
202
210
  message.put()
203
- user_acct.new_message_count+=1
204
- user_acct.put()
211
+ #user_acct.new_message_count+=1
212
+ #user_acct.put()
205
213
 
206
214
  return message
207
215
 
208
216
  def __create_message_data_from_transaction(customer_transaction):
209
217
  return {
210
- 'transaction_key' : customer_transaction.key_in_str,
218
+ 'reward_transaction_key' : customer_transaction.key_in_str,
211
219
 
212
220
  }
213
221
 
@@ -215,7 +223,13 @@ def __create_message_data_from_redemption_catalogue(redemption_catalogue_transac
215
223
  return {
216
224
  'redemption_catalogue_transaction_key' : redemption_catalogue_transaction.key_in_str,
217
225
 
218
- }
226
+ }
227
+
228
+ def __create_message_data_from_redemption(redemption_transaction):
229
+ return {
230
+ 'redemption_transaction_key' : redemption_transaction.key_in_str,
231
+
232
+ }
219
233
 
220
234
  def __create_entiled_message_from_customer_transaction(customer_transaction):
221
235
 
@@ -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):
@@ -19,6 +19,26 @@ from trexlib.utils.common.common_util import sort_list, sort_dict_list
19
19
  #logger = logging.getLogger('model')
20
20
  logger = logging.getLogger('debug')
21
21
 
22
+ def create_schedule_program(merchant_acct, program):
23
+ if program.reward_base in (program_conf.SCHEDULE_BASED_PROGRAM):
24
+
25
+ if program.reward_base == program_conf.REWARD_BASE_ON_BIRTHDAY:
26
+ if program.giveaway_reward_when == program_conf.PROGRAM_SCHEDULE_TYPE_MONTH_START:
27
+ MerchantScheduleProgram.create_first_day_of_month_schedule_program(merchant_acct, program)
28
+
29
+ elif program.giveaway_reward_when == program_conf.ADVANCE_IN_DAY:
30
+ MerchantScheduleProgram.create_daily_schedule_program(merchant_acct, program)
31
+
32
+ elif program.reward_base == program_conf.REWARD_BASE_ON_GIVEAWAY:
33
+ if program.giveaway_system_condition == program_conf.GIVEAWAY_SYSTEM_CONDITION_MEMBERSHIP_YEAR:
34
+ MerchantScheduleProgram.create_daily_schedule_program(merchant_acct, program)
35
+
36
+
37
+
38
+ def remove_schedule_program(program):
39
+ if program.reward_base in (program_conf.SCHEDULE_BASED_PROGRAM):
40
+ MerchantScheduleProgram.remove_by_merchant_program(program)
41
+
22
42
  class BaseProgram(BaseNModel, DictModel):
23
43
  reward_base = ndb.StringProperty(required=True, choices=set(program_conf.REWARD_BASE_SET))
24
44
  reward_format = ndb.StringProperty(required=False, choices=set(program_conf.REWARD_FORMAT_SET))
@@ -164,9 +184,9 @@ class BaseProgram(BaseNModel, DictModel):
164
184
  program.put()
165
185
 
166
186
  return program
167
-
187
+ '''
168
188
  @classmethod
169
- def __create_schedule_program(cls, merchant_acct, program):
189
+ def create_schedule_program(cls, merchant_acct, program):
170
190
  if program.reward_base in (program_conf.SCHEDULE_BASED_PROGRAM):
171
191
 
172
192
  if program.reward_base == program_conf.REWARD_BASE_ON_BIRTHDAY:
@@ -182,9 +202,10 @@ class BaseProgram(BaseNModel, DictModel):
182
202
 
183
203
 
184
204
  @classmethod
185
- def __remove_schedule_program(cls, program):
205
+ def remove_schedule_program(cls, program):
186
206
  if program.reward_base in (program_conf.SCHEDULE_BASED_PROGRAM):
187
207
  MerchantScheduleProgram.remove_by_merchant_program(program)
208
+ '''
188
209
 
189
210
  @classmethod
190
211
  @model_transactional(desc="publish_program")
@@ -196,7 +217,7 @@ class BaseProgram(BaseNModel, DictModel):
196
217
  merchant_acct = program.merchant_acct
197
218
  merchant_acct.update_published_program(program.to_configuration())
198
219
 
199
- cls.__create_schedule_program(merchant_acct, program)
220
+ create_schedule_program(merchant_acct, program)
200
221
 
201
222
  @classmethod
202
223
  @model_transactional(desc="archive_program")
@@ -208,7 +229,7 @@ class BaseProgram(BaseNModel, DictModel):
208
229
  merchant_acct = program.merchant_acct
209
230
  merchant_acct.remove_program_from_published_program_configuration(program.key_in_str)
210
231
 
211
- cls.__remove_schedule_program(program)
232
+ remove_schedule_program(program)
212
233
 
213
234
 
214
235
  @classmethod
@@ -231,7 +252,7 @@ class BaseProgram(BaseNModel, DictModel):
231
252
  merchant_acct = program.merchant_acct
232
253
  merchant_acct.update_published_program(program.to_configuration())
233
254
 
234
- cls.__create_schedule_program(merchant_acct, program)
255
+ create_schedule_program(merchant_acct, program)
235
256
 
236
257
 
237
258
  @classmethod
@@ -254,7 +275,7 @@ class BaseProgram(BaseNModel, DictModel):
254
275
  merchant_acct = program.merchant_acct
255
276
  merchant_acct.remove_program_from_published_program_configuration(program.key_in_str)
256
277
 
257
- cls.__remove_schedule_program(program)
278
+ remove_schedule_program(program)
258
279
 
259
280
  def to_configuration(self):
260
281
  program_configuration = {
@@ -698,6 +719,78 @@ class MerchantTierRewardProgram(MerchantProgram):
698
719
 
699
720
  return reward_settings_list
700
721
 
722
+ @staticmethod
723
+ @model_transactional(desc="publish_program")
724
+ def publish_program(program):
725
+ program.completed_status = program_conf.PROGRAM_STATUS_PUBLISH
726
+ program.published_datetime = datetime.now()
727
+ program.put()
728
+
729
+ merchant_acct = program.merchant_acct
730
+ merchant_acct.update_published_program(program.to_configuration())
731
+
732
+ create_schedule_program(merchant_acct, program)
733
+
734
+ @staticmethod
735
+ @model_transactional(desc="archive_program")
736
+ def archive_program(program):
737
+ program.archived = True
738
+ program.archived_datetime = datetime.now()
739
+ program.put()
740
+
741
+ merchant_acct = program.merchant_acct
742
+ #merchant_acct.remove_tier_program_from_published_tier_program_configuration(program.key_in_str)
743
+ merchant_acct.remove_program_from_published_program_configuration(program.key_in_str)
744
+
745
+ remove_schedule_program(program)
746
+
747
+ @staticmethod
748
+ @model_transactional(desc="enable program")
749
+ def enable(program, modified_by=None):
750
+ program.enabled = True
751
+
752
+ modified_by_username = None
753
+
754
+ if is_not_empty(modified_by):
755
+ if isinstance(modified_by, MerchantUser):
756
+ modified_by_username = modified_by.username
757
+
758
+ program.modified_by = modified_by.create_ndb_key()
759
+ program.modified_by_username = modified_by_username
760
+
761
+ program.put()
762
+
763
+ if program.is_published:
764
+ merchant_acct = program.merchant_acct
765
+ #merchant_acct.update_published_tier_program(program.to_configuration())
766
+ merchant_acct.update_published_program(program.to_configuration())
767
+
768
+ create_schedule_program(merchant_acct, program)
769
+
770
+
771
+ @classmethod
772
+ @model_transactional(desc="disable program")
773
+ def disable(cls, program, modified_by=None):
774
+ program.enabled = False
775
+
776
+ modified_by_username = None
777
+
778
+ if is_not_empty(modified_by):
779
+ if isinstance(modified_by, MerchantUser):
780
+ modified_by_username = modified_by.username
781
+ program.modified_by = modified_by.create_ndb_key()
782
+
783
+ program.modified_by_username = modified_by_username
784
+
785
+ program.put()
786
+
787
+ if program.is_published:
788
+ merchant_acct = program.merchant_acct
789
+ #merchant_acct.remove_tier_program_from_published_tier_program_configuration(program.key_in_str)
790
+ merchant_acct.remove_program_from_published_program_configuration(program.key_in_str)
791
+
792
+ remove_schedule_program(program)
793
+
701
794
  @staticmethod
702
795
  def create(merchant_acct, label=None, is_tier_recycle=True, is_show_progress=True, reward_format=None,
703
796
  desc=None, start_date=None, end_date=None, created_by=None):
@@ -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