diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index f546d57..f56d882 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -34,6 +34,10 @@ jobs: mkdir -p /root/hshop/backend/ printf "%s" "${{ secrets.ENV_FILE_CONTENT }}" > /root/hshop/backend/.env.local + mkdir -p /root/hshop/frontend/ + printf "%s" "${{ secrets.FRONTEND_ENV }}" > /root/hshop/frontend/.env + + - name: Build and start Docker containers uses: appleboy/ssh-action@v0.1.6 with: diff --git a/backend/account/migrations/0025_alter_pushsubscription_options_and_more.py b/backend/account/migrations/0025_alter_pushsubscription_options_and_more.py new file mode 100644 index 0000000..fbf9933 --- /dev/null +++ b/backend/account/migrations/0025_alter_pushsubscription_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.2 on 2025-03-28 15:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0024_alter_user_birth_date'), + ] + + operations = [ + migrations.AlterModelOptions( + name='pushsubscription', + options={'verbose_name': 'اشتراک نوتیفیکیشن', 'verbose_name_plural': 'اشتراک های نوتیفیکیشن'}, + ), + migrations.AlterField( + model_name='useraddressmodel', + name='is_main', + field=models.BooleanField(default=False, verbose_name='ادرس اصلی کاربر'), + ), + ] diff --git a/backend/azbankgateways/migrations/0008_alter_bank_order.py b/backend/azbankgateways/migrations/0008_alter_bank_order.py new file mode 100644 index 0000000..72bd58e --- /dev/null +++ b/backend/azbankgateways/migrations/0008_alter_bank_order.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.2 on 2025-03-28 15:39 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('azbankgateways', '0007_alter_bank_order'), + ('order', '0025_alter_ordermodel_order_id'), + ] + + operations = [ + migrations.AlterField( + model_name='bank', + name='order', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bank_records', to='order.ordermodel', verbose_name='سفارش'), + ), + ] diff --git a/backend/core/settings/base.py b/backend/core/settings/base.py index 4710cfd..14c58ba 100644 --- a/backend/core/settings/base.py +++ b/backend/core/settings/base.py @@ -244,7 +244,7 @@ AZ_IRANIAN_BANK_GATEWAYS = { "ZIBAL": { "MERCHANT_CODE": "zibal", "SANDBOX": True - }, + } }, "IS_SAMPLE_FORM_ENABLE": True, "DEFAULT": "ZIBAL", @@ -255,5 +255,6 @@ AZ_IRANIAN_BANK_GATEWAYS = { "BANK_PRIORITIES": [ "ZIBAL", ], - "IS_SAFE_GET_GATEWAY_PAYMENT": False # better to be True -} \ No newline at end of file + "IS_SAFE_GET_GATEWAY_PAYMENT": True # better to be True +} +DEFAULT_TAX_RATE = 20 \ No newline at end of file diff --git a/backend/core/settings/production.py b/backend/core/settings/production.py index a641284..b6d1107 100644 --- a/backend/core/settings/production.py +++ b/backend/core/settings/production.py @@ -2,7 +2,7 @@ from .base import * from .unfold_conf import * -ALLOWED_HOSTS = ['127.0.0.1', 'localhost', DOMAIN, API_DOMAIN] +ALLOWED_HOSTS = ['127.0.0.1', 'localhost', DOMAIN, API_DOMAIN, '0.0.0.0',] CSRF_TRUSTED_ORIGINS = [ f"https://{DOMAIN}", f"http://{DOMAIN}", diff --git a/backend/core/views.py b/backend/core/views.py index d57f36a..be623df 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -52,7 +52,7 @@ def random_data(): "kpi": [ { "title": "گوشی Iphone 16 pro", - "metric": f"${intcomma(f"{random.uniform(1000, 9999):.02f}")}", + "metric": f"${intcomma(f'{random.uniform(1000, 9999):.02f}')}", "footer": mark_safe( f'+{intcomma(f"{random.uniform(1, 9):.02f}")}% درصد فروش کل' ), @@ -65,14 +65,14 @@ def random_data(): }, { "title": "لپ تاپ Macbook Pro M3", - "metric": f"${intcomma(f"{random.uniform(1000, 9999):.02f}")}", + "metric": f"${intcomma(f'{random.uniform(1000, 9999):.02f}')}", "footer": mark_safe( f'+{intcomma(f"{random.uniform(1, 9):.02f}")}% درصد فروش کل' ), }, { "title": "ساعت هوشمند Apple Watch 8", - "metric": f"${intcomma(f"{random.uniform(1000, 9999):.02f}")}", + "metric": f"${intcomma(f'{random.uniform(1000, 9999):.02f}')}", "footer": mark_safe( f'+{intcomma(f"{random.uniform(1, 9):.02f}")}% درصد فروش کل' ), diff --git a/backend/order/migrations/0025_alter_ordermodel_order_id.py b/backend/order/migrations/0025_alter_ordermodel_order_id.py new file mode 100644 index 0000000..5c1df71 --- /dev/null +++ b/backend/order/migrations/0025_alter_ordermodel_order_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2025-03-28 15:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0024_orderitemmodel_discount_ordermodel_order_id'), + ] + + operations = [ + migrations.AlterField( + model_name='ordermodel', + name='order_id', + field=models.PositiveIntegerField(blank=True, null=True, unique=True, verbose_name='شماره سفارش'), + ), + ] diff --git a/backend/order/models.py b/backend/order/models.py index 8d7ba6a..675bd07 100644 --- a/backend/order/models.py +++ b/backend/order/models.py @@ -66,9 +66,11 @@ class OrderModel(models.Model): def save(self, *args, **kwargs): + # genrate order id if not self.pk: last_instance = self.__class__.objects.order_by("pk").last() self.order_id = (last_instance.pk + 1001) if last_instance else 1001 + super().save(*args, **kwargs) diff --git a/backend/order/signals.py b/backend/order/signals.py index 63cacc1..793f46e 100644 --- a/backend/order/signals.py +++ b/backend/order/signals.py @@ -3,6 +3,8 @@ from django.dispatch import receiver from .models import OrderModel from account.models import PushSubscription import ghasedak_sms +from .tasks import send_change_status_notif, send_change_status_sms + @receiver(pre_save, sender=OrderModel) def order_status_changed(sender, instance, **kwargs): @@ -10,36 +12,18 @@ def order_status_changed(sender, instance, **kwargs): previous = OrderModel.objects.get(pk=instance.pk) if previous.status != instance.status: - send_change_status_notif(instance) - send_change_status_sms(instance) + new_status = instance.get_status_display() + send_change_status_notif.delay(instance.pk, new_status) + send_change_status_sms.delay(instance.pk, new_status) + + if previous.status == 'CART' and instance.status == 'ADMIN_PENDING': + # update_cart_price_fields() + # update_sell_data() + # update_quantity() + pass -def send_change_status_notif(instance): - user_subs = PushSubscription.objects.filter(user=instance.user) - for user_sub in user_subs: - try: - user_sub.send_notif(f'سفارش شما به {instance.get_status_display()} تغییر کرد', f'سفارش شما به {instance.get_status_display()} تغییر کرد', ProductImageModel.objects.all().first().image.url) - except: - print('log later send notif error') - - -def send_change_status_sms(instance): - sms_api = ghasedak_sms.Ghasedak(api_key="1227eaaddcba72bcb0169b37032cf16ae9ac6ed8b3b7c2768b74e2ee351d1b52gyRe3AGomZRPTNEd") - - - response = sms_api.send_single_sms( - ghasedak_sms.SendSingleSmsInput( - message=f'سفارش شما به {instance.get_status_display()} تغییر کرد', - receptor=instance.user.phone, - line_number='30005006004095', - client_reference_id=str(instance.user.pk) - ) - ) - if response['statusCode'] == 200: - print('done log later') - else: - print(f'error: {response}') def update_cart_price_fields(order): diff --git a/backend/order/tasks.py b/backend/order/tasks.py index e1449c3..1a87f1e 100644 --- a/backend/order/tasks.py +++ b/backend/order/tasks.py @@ -4,7 +4,9 @@ from azbankgateways import ( models as bank_models, default_settings as settings, ) - +from .models import OrderModel +from account.models import PushSubscription +import ghasedak_sms from celery import shared_task @@ -23,4 +25,34 @@ def udpate_bank_status(): if bank_record.is_success: logging.debug("This record is verify now.", extra={"pk": bank_record.pk}) - print('update bank record is done') \ No newline at end of file + return 'update bank record is done' + + +@shared_task +def send_change_status_notif(instance_pk, new_status): + instance = OrderModel.objects.get(pk=instance_pk) + user_subs = PushSubscription.objects.filter(user=instance.user) + for user_sub in user_subs: + try: + user_sub.send_notif(f'سفارش شما به {new_status} تغییر کرد', f'سفارش شما به {new_status} تغییر کرد', ProductImageModel.objects.all().first().image.url) + except: + print('log later send notif error') + +@shared_task +def send_change_status_sms(instance_pk, new_status): + instance = OrderModel.objects.get(pk=instance_pk) + sms_api = ghasedak_sms.Ghasedak(api_key="1227eaaddcba72bcb0169b37032cf16ae9ac6ed8b3b7c2768b74e2ee351d1b52gyRe3AGomZRPTNEd") + + + response = sms_api.send_single_sms( + ghasedak_sms.SendSingleSmsInput( + message=f'سفارش شما به {new_status} تغییر کرد', + receptor=instance.user.phone, + line_number='30005006004095', + client_reference_id=str(instance.user.pk) + ) + ) + if response['statusCode'] == 200: + return 'done log later' + else: + return f'error: {response}' \ No newline at end of file diff --git a/backend/order/views.py b/backend/order/views.py index 19a01ee..335c647 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -197,7 +197,7 @@ class OrderGetView(APIView): from rest_framework import serializers class BankTypeSerializer(serializers.Serializer): - gateway_type = serializers.ChoiceField(choices=['BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'ZIBAL', 'BAHAMTA', 'MELLAT', 'PAYV1']) + gateway_type = serializers.ChoiceField(choices=['ZIBAL', 'BMI', 'SEP', 'ZARINPAL', 'IDPAY', 'BAHAMTA', 'MELLAT', 'PAYV1']) class PaymentView(APIView): @@ -210,18 +210,19 @@ class PaymentView(APIView): def post(self, request): print(request.data.get('gateway_type')) cart_order = get_object_or_404(OrderModel, user=request.user, status='CART') - amount = 5000 + amount = 10000 user_mobile_number = request.user.phone factory = bankfactories.BankFactory() try: bank = ( - factory.auto_create() + factory.create( + bank_models.BankType.ZIBAL + ) ) bank.set_request(request) bank.set_amount(amount) - - bank.set_client_callback_url(request.build_absolute_uri(reverse("callback-gateway"))) + bank.set_client_callback_url(reverse("callback-gateway")) print(reverse('callback-gateway')) bank.set_mobile_number(user_mobile_number) @@ -230,7 +231,7 @@ class PaymentView(APIView): # cart_order.save() bank_record.order = cart_order bank_record.save() - return Response(bank.redirect_gateway().url) + return Response(bank.get_gateway()) except AZBankGatewaysException as e: print(e) return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) diff --git a/backend/product/migrations/0035_alter_attributetype_options_and_more.py b/backend/product/migrations/0035_alter_attributetype_options_and_more.py new file mode 100644 index 0000000..d426fc7 --- /dev/null +++ b/backend/product/migrations/0035_alter_attributetype_options_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.2 on 2025-03-28 15:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0034_remove_productvariant_max_price_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='attributetype', + options={'verbose_name': 'نوع متغییر محصول', 'verbose_name_plural': 'نوع های متغییر محصول'}, + ), + migrations.AlterModelOptions( + name='attributevalue', + options={'verbose_name': 'مقدار متغییر محصول', 'verbose_name_plural': 'مقدار های متغییر محصول'}, + ), + migrations.AlterField( + model_name='attributetype', + name='name', + field=models.CharField(max_length=100, verbose_name='نام نوع متغییر'), + ), + ] diff --git a/backend/ticket/migrations/0019_alter_attachment_options.py b/backend/ticket/migrations/0019_alter_attachment_options.py new file mode 100644 index 0000000..14a4e78 --- /dev/null +++ b/backend/ticket/migrations/0019_alter_attachment_options.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.2 on 2025-03-28 15:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ticket', '0018_alter_ticket_created_at_alter_ticket_updated_at'), + ] + + operations = [ + migrations.AlterModelOptions( + name='attachment', + options={'verbose_name': 'پیوست تیکت', 'verbose_name_plural': 'پیوست های تیکت'}, + ), + ] diff --git a/docker-compose.yml b/docker-compose.yml index 756bfc3..577d9f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,9 +10,10 @@ services: networks: - default environment: - - API_BASE_URL="https://api.heymlz.com" - - DEBUG="false" - - NUXT_IMAGE_DOMAINS="https://c262408.parspack.net" + - API_BASE_URL=https://api.heymlz.com + - DEBUG=false + - NUXT_IMAGE_DOMAINS=https://c262408.parspack.net + restart: always django: container_name: shop_backend @@ -28,6 +29,7 @@ services: - media_data:/app/static networks: - default + restart: always db: container_name: shop_db @@ -42,6 +44,7 @@ services: - "5434:5432" networks: - default + restart: always db-backup: container_name: shop_backup @@ -62,6 +65,7 @@ services: - backups:/backups networks: - default + restart: always redis: @@ -71,6 +75,7 @@ services: - "6379:6379" networks: - default + restart: always celery_worker: container_name: shop_celery_worker @@ -86,6 +91,7 @@ services: - CELERY_BROKER_URL=redis://redis:6379/0 networks: - default + restart: always celery_beat: container_name: shop_celery_beat @@ -101,6 +107,7 @@ services: - CELERY_BROKER_URL=redis://redis:6379/0 networks: - default + restart: always volumes: