diff --git a/SQL/site_data.sql b/SQL/site_data.sql
index 6c58c21..b2ee4c8 100644
--- a/SQL/site_data.sql
+++ b/SQL/site_data.sql
@@ -49,6 +49,7 @@ ALTER TABLE members ADD profile_completed timestamp without time zone DEFAULT NU
ALTER TABLE members ADD option_name VARCHAR(100) REFERENCES subscription_options(option_name);
ALTER TABLE members ADD next_billing timestamp without time zone;
ALTER TABLE members ADD trial_end timestamp without time zone;
+ALTER TABLE members ADD last_login timestamp without time zone DEFAULT now();
-- bALTER TABLE members ADD option_name VARCHAR(100) REFERENCES subscription_options(option_name);
CREATE TABLE members_profile(
@@ -111,6 +112,22 @@ CREATE TABLE products (
ALTER TABLE products ADD start_url VARCHAR(100);
+ ALTER TABLE products ADD list_order INT DEFAULT 0;
+ ALTER TABLE products ADD contacts INT DEFAULT 0;
+ ALTER TABLE products ADD comments INT DEFAULT 0;
+
+
+UPDATE products SET contacts = 1 WHERE product_id IN ('A000001','A000002');
+UPDATE products SET comments = 1 WHERE product_id IN ('A000003','A000004');
+
+ALTER TABLE products ADD blog_product_id VARCHAR(25);
+UPDATE products SET blog_product_id='A000003' WHERE product_id = 'A000001';
+UPDATE products SET blog_product_id='A000004' WHERE product_id = 'A000002';
+
+--- initial set
+UPDATE products SET list_order = 10*id;
+UPDATE products SET name='Open-EMR' WHERE product_id = 'A000005';
+
--- DEVELOPMENT
UPDATE products SET start_url = 'A1.devprov.mermsemr.com' WHERE product_id = 'A000001';
UPDATE products SET start_url = 'A2.devprov.mermsemr.com' WHERE product_id = 'A000002';
@@ -248,6 +265,53 @@ merms_panel=# select product_id,description from products;
A000005 | Get Open EMR for practice management
(5 rows)
+
+CREATE TABLE products_colorstyle (
+ id SERIAL,
+ uid uuid DEFAULT uuid_generate_v4(),
+ product_id VARCHAR(25) REFERENCES products(product_id),
+ name VARCHAR(55) NOT NULL,
+ color_style VARCHAR(55) NOT NULL,
+ color_code VARCHAR(9) NOT NULL,
+ status INT DEFAULT 0,
+ added timestamp without time zone DEFAULT now()
+ );
+ ALTER TABLE ONLY products_colorstyle
+ ADD CONSTRAINT products_colorstyle_id_key UNIQUE (id);
+
+ALTER TABLE products_colorstyle OWNER TO merms_panel;
+
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Blue','blue-theme.css','0000FF');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Crocus','crocus-theme.css','9172EC');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Green','green-theme.css','00FF00');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Magenta','magenta-theme.css','FF00FF');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Pink','pink-theme.css','FFC0CB');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Purple','purple-theme.css','800080');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Skyblue','skyblue-theme.css','87CEEB');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Red','red-theme.css','FF0000');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000001','Violet','violet-theme.css','8F00FF');
+
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Blue','blue-theme.css','0000FF');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Crocus','crocus-theme.css','9172EC');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Green','green-theme.css','00FF00');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Magenta','magenta-theme.css','FF00FF');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Pink','pink-theme.css','FFC0CB');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Purple','purple-theme.css','800080');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Skyblue','skyblue-theme.css','87CEEB');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Red','red-theme.css','FF0000');
+INSERT INTO products_colorstyle (product_id, name, color_style, color_code ) VALUES ('A000002','Violet','violet-theme.css','8F00FF');
+
+
+
+{`nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
+
+
+
+
+
+
+
+
CREATE TABLE products_templates (
id SERIAL,
uid uuid DEFAULT uuid_generate_v4(),
@@ -264,6 +328,9 @@ merms_panel=# select product_id,description from products;
ALTER TABLE products_templates OWNER TO merms_panel;
+
+
+
INSERT INTO products_templates(product_id,name,provision_name,status)
VALUES(
'A000001',
@@ -350,22 +417,52 @@ INSERT INTO products (name,description,status,product_id, banner) VALUES ('Perso
INSERT INTO products (name,description,status,product_id, banner) VALUES ('Professional Blog','Booster your practice with engaging contents',1,'A000004', 'banner.jpg');
INSERT INTO products (name,description,status,product_id, banner) VALUES ('Practice EMR','Get Open EMR for practice management',1,'A000005', 'banner.jpg');
-INSERT INTO products (name,description,status,product_id, banner) VALUES ('Mers Practice','Get Open EMR for practice management',1,'A000006', 'banner.jpg');
-UPDATE products SET start_url = 'm.ehr.mermsemr.com' WHERE product_id = 'A000006';
+-- NEW PRODUCT------------------------------------------------------
+
+
+
+INSERT INTO products (name,description,status,product_id, banner, start_url)
+VALUES ('MERMs Practice',
+ 'Get Merms EMR for your Practice Management',
+ 5,
+ 'A000006',
+ 'p6.jpg',
+ 'm.ehr.mermsemr.com');
+
+-- UPDATE products SET start_url = 'm.ehr.mermsemr.com' WHERE product_id = '';
INSERT INTO products_details (product_id,details) VALUES ('A000006', '
-
OpenEMR is the most popular open source electronic health records and medical practice management solution. OpenEMR is a community of passionate volunteers and contributors dedicated to guarding OpenEMR status as a free, open source software solution for medical practices with a commitment to openness, kindness and cooperation.
+
OpenEMR is the most popular open source electronic health records and medical practice management solution. Merms EMR is a community of passionate volunteers and contributors dedicated to guarding OpenEMR status as a free, open source software solution for medical practices with a commitment to openness, kindness and cooperation.
-Activate to deploy OpenEMR for your practice
-
-URL: https://www.open-emr.org/
');
+Activate to deploy MERMS Emr for your practice
+ ');
UPDATE products_details SET sale_text =
'
Start free for 1 month, and customize your product with additional features as you see fit. You''re in control-you can cancel anytime.
-
' WHERE product_id= 'products_details';
+
' WHERE product_id= 'A000006';
+
+
+INSERT INTO products_templates(product_id,name,provision_name,status)
+VALUES(
+ 'A000006',
+ 'Template F01',
+ 'registry.chiefsoft.com/products/merms-emr-001:latest',
+ 1);
+
+INSERT INTO products_templates(product_id,name,provision_name,status)
+VALUES(
+ 'A000006',
+ 'Template F02',
+ 'registry.chiefsoft.com/products/merms-emr-002:latest',
+ 1);
+
+
+-- UPDATE products SET start_url = 'm.ehr.mermsemr.com' WHERE product_id = 'A000006';
+-- UPDATE products SET status = 5 WHERE product_id = 'A000006';
+-- END 000 Product --------------------------------------------------
@@ -670,6 +767,8 @@ CREATE TABLE office_users(
ALTER TABLE ONLY office_users
ADD CONSTRAINT office_users_id_key UNIQUE (id);
+ALTER TABLE office_users ALTER COLUMN password TYPE VARCHAR(250);
+
ALTER TABLE office_users OWNER TO merms_panel;
INSERT INTO office_users (username, password, firstname, lastname, acc_level) VALUES ('mermsadmin','password','Merms','Admin',1000);
diff --git a/app/api/enums/settings_items_data.py b/app/api/enums/settings_items_data.py
index bf25a02..bbf160a 100644
--- a/app/api/enums/settings_items_data.py
+++ b/app/api/enums/settings_items_data.py
@@ -79,6 +79,6 @@ class SettingsItemsData:
def get_site_blog_connect_settings():
data = {
"boolean_blog_connect_show": {"name": 'Show Blog Section', "controls": 'SELECT_NO_YES',
- "active": True, "list_order": 0},
+ "active": True, "list_order": 0},
}
return data
\ No newline at end of file
diff --git a/app/api/routes/routes.py b/app/api/routes/routes.py
index 9b7fec8..d3bbb77 100644
--- a/app/api/routes/routes.py
+++ b/app/api/routes/routes.py
@@ -115,6 +115,7 @@ def merms_account():
response = AccountService.process_request(data)
return response
+
@api.route("/panel/account/profile", methods=["POST"])
@jwt_required()
def merms_account_profile():
@@ -189,6 +190,16 @@ def get_myproduct_templates():
return response
+@api.route("/panel/account/products/color-styles", methods=["POST"])
+# @token_required
+def get_myproduct_colorstyles():
+ # Call the ColorStyles service
+ data = request.get_json()
+ # logger.info(f"Route Product ColorStyles Data ==>>>> {data}")
+ response = MyProductsService.mpproduct_colostyles_data(data)
+ return response
+
+
@api.route("/panel/account/template/activate", methods=["POST"])
# @token_required
def get_myproduct_templates_activate():
@@ -205,6 +216,7 @@ def merms_contacts():
response = ContactService.process_request(data)
return response
+
@api.route("/panel/comments", methods=["POST"])
def merms_site_comments():
data = request.get_json()
@@ -228,6 +240,7 @@ def myproduct_dash():
response = MyProductsService.process_request(data)
return response
+
@api.route("/panel/myproduct/external-url", methods=["POST"])
def set_external_url():
data = request.get_json()
@@ -382,6 +395,7 @@ def get_dashboard():
result = OfficeDashboardService.get_dashboard_data()
return jsonify(result)
+
@api.route('/office/country', methods=['GET'])
# @token_required
def get_office_country():
@@ -389,6 +403,7 @@ def get_office_country():
result = OfficeCountryService.get_office_country_list()
return jsonify(result)
+
@api.route('/office/set-country', methods=['POST'])
# @token_required
def set_office_country():
@@ -427,6 +442,7 @@ def get_subscriptions_list_office():
response = SubscriptionsService.get_subscription_data(filters)
return response
+
@api.route('/office/subscription-view', methods=['GET'])
# @token_required
def get_subcriptions_view_office():
@@ -438,6 +454,7 @@ def get_subcriptions_view_office():
response = OfficeDashboardService.get_subscription_view_data(filters)
return response
+
@api.route('/office/template/set-custom', methods=['POST'])
# @token_required
def get_set_custom_template_office():
@@ -464,6 +481,7 @@ def get_create_custom_template_office():
response = OfficeTemplatesService.create_custom_template(data)
return response
+
@api.route('/office/billings', methods=['GET'])
# @token_required
def get_subscription_billings_office():
@@ -490,6 +508,7 @@ def get_subscription_transaction_office():
result = OfficeDashboardService.get_payments_data(filters)
return jsonify(result)
+
@api.route('/office/recent-signup', methods=['GET'])
def get_recent_signup_office():
# Call the dashboard service
@@ -497,6 +516,7 @@ def get_recent_signup_office():
result = OfficeDashboardService.get_payments_data(filters)
return jsonify(result)
+
@api.route('/office/right-sidebar', methods=['GET'])
def get_office_sidebar():
# Call the dashboard service
@@ -504,6 +524,7 @@ def get_office_sidebar():
result = OfficeDashboardService.get_office_sidebar(filters)
return jsonify(result)
+
@api.route('/office/users', methods=['GET'])
def get_office_users():
logger.info('API::get office users')
@@ -511,6 +532,7 @@ def get_office_users():
result = OfficeUsersService.get_office_users(filters)
return jsonify(result)
+
@api.route('/office/products', methods=['GET'])
def get_product_office():
# Call the dashboard service
@@ -518,6 +540,7 @@ def get_product_office():
result = OfficeDashboardService.get_office_products(filters)
return jsonify(result)
+
@api.route('/office/product-view', methods=['GET'])
def get_product_view_office():
# Call the dashboard service
@@ -527,6 +550,7 @@ def get_product_view_office():
result = OfficeDashboardService.get_office_product_detail(filters)
return jsonify(result)
+
@api.route('/office/product-update', methods=['POST'])
def get_product_update_office():
# Call the dashboard service
@@ -556,6 +580,7 @@ def get_product_templates():
result = OfficeDashboardService.get_office_product_templates(filters)
return jsonify(result)
+
@api.route('/office/account-view', methods=['GET'])
def get_office_accoint_view():
# Call the office account viiew
@@ -568,6 +593,7 @@ def get_office_accoint_view():
# return response
return jsonify(response)
+
@api.route('/office/custom-templates', methods=['GET'])
def get_custom_templates():
# Call the dashboard service
@@ -581,6 +607,7 @@ def get_custom_templates():
result = OfficeDashboardService.get_office_custom_templates(filters)
return jsonify(result)
+
# =====================================================
@api.route('/web/contents', methods=['GET'])
# @token_required
@@ -590,6 +617,7 @@ def get_web_contents():
result = WebContentsService.get_web_contents_data(provision_uid)
return jsonify(result)
+
# =====================================================
@api.route('/web/contacts', methods=['POST'])
# @token_required
@@ -599,6 +627,7 @@ def get_web_receive_contacts():
result = ContactService.process_save_contacts(data)
return jsonify(result)
+
# =====================================================
@api.route('/web/generatives', methods=['GET'])
def get_refresh_generatives():
@@ -608,6 +637,7 @@ def get_refresh_generatives():
result = GenerativesService.process_generatives_list(data)
return jsonify(result)
+
# =====================================================
@api.route('/web/traffic', methods=['POST'])
# @token_required
@@ -636,10 +666,11 @@ def common_practice():
# Health Check Endpoint
@api.route("/testemail", methods=["GET"])
def email_check():
- data ={}
+ data = {}
AccountService.process_test_email(data)
return {"status": "ok"}, 200
+
# Health Check Endpoint
@api.route("/health", methods=["GET"])
def health_check():
diff --git a/app/api/services/myproduct.py b/app/api/services/myproduct.py
index a7d1597..3e729b4 100644
--- a/app/api/services/myproduct.py
+++ b/app/api/services/myproduct.py
@@ -10,7 +10,7 @@ from app.api.services.base_service import BaseService
from marshmallow import ValidationError
from app.extensions import db
from app.models import MembersProducts, Products, Members, ProductsDetails, ProductsDetails, ProvisionActions, \
- MembersProductsSettings, ProductsTemplates, MembersProfile, SubscriptionGenerative
+ MembersProductsSettings, ProductsTemplates, MembersProfile, SubscriptionGenerative, ProductsColorStyle
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.myproduct import MyProductSchema
from app.api.schemas.provision import ProvisionSchema
@@ -124,6 +124,63 @@ class MyProductsService(BaseService):
db.session.rollback()
return ResponseHelper.internal_server_error()
+ @staticmethod
+ def mpproduct_colostyles_data(data):
+ try:
+ with db.session.begin():
+ # logger.info(f"Incoming MyProduct data ==>>>> {data}")
+ validated_data = MyProductsService.validate_data(data, MyProductSchema())
+ token = validated_data.get('token')
+ uid = validated_data.get('uid')
+ member_data = Members.get_member_by_uid(uid)
+ member_id = member_data.id
+
+ product_id = validated_data.get('product_id')
+ color_style_data = []
+ memberSubscription = MembersProducts.get_member_product_by_product_member_id(member_id, product_id)
+ if memberSubscription:
+ colorStyles = ProductsColorStyle.get_colorstyle_by_product_id(product_id)
+ # templates = ProductsTemplates.get_template_by_product_id(product_id)
+ for t in colorStyles:
+ color_style_data.append({
+ 'id': t.id,
+ 'template_uid': t.uid,
+ 'color_style_uid': t.uid,
+ 'color_code': t.color_code,
+ 'title': t.name,
+ 'active': t.status,
+ 'added': t.added.isoformat() if t.added else None
+ })
+
+ response_data = {
+ "product_id": product_id,
+ "current_template_uid": memberSubscription.product_template if memberSubscription else None,
+ "custom_template_name": memberSubscription.custom_template if memberSubscription else '',
+ "templates": color_style_data,
+ "last_update": datetime.datetime.utcnow(),
+ }
+
+ return ResponseHelper.success(data=response_data)
+
+
+ except ValidationError as err:
+
+ logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
+ db.session.rollback()
+ return ResponseHelper.unprocessable_entity(result_description="Validation exception")
+
+ except ValueError as err:
+ logger.error(f"{getattr(err, 'messages', str(err))}")
+ db.session.rollback()
+ return ResponseHelper.error(result_description=str(err))
+
+ except Exception as e:
+ logger.error(f"An error occurred: {str(e)}", exc_info=True)
+ db.session.rollback()
+ return ResponseHelper.internal_server_error()
+
+
+
@staticmethod
def process_provision(data):
try:
diff --git a/app/models/__init__.py b/app/models/__init__.py
index 051c771..a5c793f 100644
--- a/app/models/__init__.py
+++ b/app/models/__init__.py
@@ -19,12 +19,14 @@ from .subscription_generative import SubscriptionGenerative
from .generative_results import GenerativeResults
from .office_users import OfficeUsers
from .custom_templates import CustomTemplates
+from .products_colorstyle import ProductsColorStyle
from .country import Country
__all__ = ['Members', 'Account', 'Products',
'MembersProducts', 'MembersActions', 'MembersPending', 'ProductsDetails',
'ProvisionActions', 'MembersProductsRefresh', 'MembersProductsSettings',
'PasswordReset', 'MembersProfile', 'SubscriptionOptions', 'SubscriptionOptionsItems',
- 'ProductsTemplates', 'Payments', 'PaymentsSession', 'SubscriptionGenerative', 'GenerativeResults',
- 'CustomTemplates','Country',
+ 'ProductsTemplates', 'ProductsColorStyle', 'Payments', 'PaymentsSession',
+ 'SubscriptionGenerative', 'GenerativeResults',
+ 'CustomTemplates', 'Country',
'OfficeUsers']
diff --git a/app/models/products_colorstyle.py b/app/models/products_colorstyle.py
new file mode 100644
index 0000000..3958b04
--- /dev/null
+++ b/app/models/products_colorstyle.py
@@ -0,0 +1,59 @@
+#
+
+from datetime import datetime, timezone
+from app.extensions import db
+from app.models.charge import Charge
+from sqlalchemy.orm import relationship
+from sqlalchemy.sql import func
+
+
+class ProductsColorStyle(db.Model):
+ __tablename__ = 'products_colorstyle'
+
+ id = db.Column(db.String, primary_key=True)
+ uid = db.Column(db.String, nullable=False)
+ product_id = db.Column(db.String, nullable=False)
+ name = db.Column(db.String, nullable=False)
+ color_style = db.Column(db.String, nullable=False)
+ color_code = db.Column(db.String, nullable=False)
+ status = db.Column(db.Integer, nullable=True, default=1)
+ added = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
+
+ @classmethod
+ def get_colorstyle_by_product_id(cls, product_id):
+ templates = cls.query.filter_by(product_id=str(product_id)).all()
+
+ if not templates:
+ # raise ValueError(f"Templates with Product ID {product_id} not found")
+ return None
+ return templates
+
+ @classmethod
+ def get_colorstyle_for_office(cls, filters):
+ templates = cls.query.all()
+
+ if not templates:
+ raise ValueError(f"Templates not found")
+ return templates
+
+ # @classmethod
+ # def get_template_by_uid(cls, template_uid):
+ # selTemplate = cls.query.filter_by(uif=template_uid).first()
+ # if not selTemplate:
+ # return None
+ # return selTemplate
+
+ def to_dict(self):
+ return {
+ "id": self.id,
+ "uid": self.uid,
+ "product_id": self.product_id,
+ "name": self.name,
+ "color_style": self.color_style,
+ "color_code": self.color_code,
+ "status": self.status,
+ "added": self.added.isoformat() if self.added else None
+ }
+
+ def __repr__(self):
+ return f''
diff --git a/app/models/products_templates.py b/app/models/products_templates.py
index f61d5bd..535a7a7 100644
--- a/app/models/products_templates.py
+++ b/app/models/products_templates.py
@@ -4,6 +4,7 @@ from app.models.charge import Charge
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
+
class ProductsTemplates(db.Model):
__tablename__ = 'products_templates'
@@ -16,7 +17,6 @@ class ProductsTemplates(db.Model):
provision_name = db.Column(db.String, nullable=False)
added = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
-
@classmethod
def get_template_by_product_id(cls, product_id):
templates = cls.query.filter_by(product_id=str(product_id)).all()
@@ -41,7 +41,6 @@ class ProductsTemplates(db.Model):
return None
return selTemplate
-
def to_dict(self):
return {
"id": self.id,
@@ -51,8 +50,8 @@ class ProductsTemplates(db.Model):
"status": self.status,
"owner_uid": self.owner_uid,
"provision_name": self.provision_name,
- "provision_name": self.provision_name
+ "added": self.added.isoformat() if self.added else None
}
def __repr__(self):
- return f''
\ No newline at end of file
+ return f''