diff --git a/.gitea/workflows/kub-deploy.yml b/.gitea/workflows/kub-deploy.yml index 6c3a65f..2b2fb69 100644 --- a/.gitea/workflows/kub-deploy.yml +++ b/.gitea/workflows/kub-deploy.yml @@ -73,9 +73,9 @@ jobs: # Apply manifests and restart sshpass -e ssh -o StrictHostKeyChecking=no root@${{ env.K8S_SERVER }} " - kubectl apply -f /tmp/backoffice-deployment.yaml && - kubectl rollout restart deployment/backoffice && - kubectl rollout status deployment/backoffice --timeout=180s && + kubectl apply -n kbs-stage -f /tmp/backoffice-deployment.yaml && + kubectl -n kbs-stage rollout restart deployment/backoffice && + kubectl -n kbs-stage rollout status deployment/backoffice --timeout=180s && rm -f /tmp/backoffice-deployment.yaml " echo "✅ Deployed!" diff --git a/.gitignore b/.gitignore index 3508f6e..2f9a25a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ # ---> VisualStudio ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. -## +## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore -# User-specific files +# User-specific files *.rsuser *.suo *.user diff --git a/k8s/staging/backoffice-deployment.yaml b/k8s/staging/backoffice-deployment.yaml index 0b1e8e2..336cd1d 100644 --- a/k8s/staging/backoffice-deployment.yaml +++ b/k8s/staging/backoffice-deployment.yaml @@ -4,7 +4,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: backoffice - namespace: default + namespace: kbs-stage labels: app: backoffice spec: @@ -20,7 +20,7 @@ spec: containers: - name: backoffice image: 185.252.31.44:30080/admin/backoffice:latest - imagePullPolicy: Always + imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http @@ -43,7 +43,7 @@ apiVersion: v1 kind: Service metadata: name: backoffice-svc - namespace: default + namespace: kbs-stage spec: selector: app: backoffice @@ -58,7 +58,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: backoffice-ingress - namespace: default + namespace: kbs-stage annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/ssl-redirect: "true" diff --git a/src/BackOffice/BackOffice.csproj b/src/BackOffice/BackOffice.csproj index 29ae5c3..080f774 100644 --- a/src/BackOffice/BackOffice.csproj +++ b/src/BackOffice/BackOffice.csproj @@ -143,7 +143,7 @@ - + diff --git a/src/BackOffice/Common/Utilities/RouteConstance.cs b/src/BackOffice/Common/Utilities/RouteConstance.cs index 9da68a5..6298da1 100644 --- a/src/BackOffice/Common/Utilities/RouteConstance.cs +++ b/src/BackOffice/Common/Utilities/RouteConstance.cs @@ -8,6 +8,7 @@ public static class RouteConstance public const string Package = "/PackagePage/"; public const string Role = "/RolePage/"; public const string UserPage = "/UserPage/"; + public const string InvitationsReport = "/InvitationsReportPage/"; public const string UserOrder = "/UserOrderPage/"; public const string Orders = "/OrdersPage/"; public const string OrdersSalesReports = "/OrdersSalesReportsPage/"; diff --git a/src/BackOffice/Pages/Commission/WeeklyReports.razor b/src/BackOffice/Pages/Commission/WeeklyReports.razor index b97d595..75df16b 100644 --- a/src/BackOffice/Pages/Commission/WeeklyReports.razor +++ b/src/BackOffice/Pages/Commission/WeeklyReports.razor @@ -65,6 +65,11 @@ SortMode="SortMode.Multiple"> + + + @(string.IsNullOrEmpty(context.Item.PackageTitle) ? "—" : context.Item.PackageTitle) + + @context.Item.TotalPoolAmount.ToString("N0") تومان @@ -203,6 +208,8 @@ { WeekDefinitionId = x.WeekDefinitionId, WeekDisplayName = x.WeekDisplayName, + PackageId = x.PackageId, + PackageTitle = x.PackageTitle, TotalPoolAmount = x.TotalPoolAmount, TotalBalances = x.TotalBalances, ValuePerBalance = x.ValuePerBalance, @@ -249,6 +256,8 @@ { public long WeekDefinitionId { get; set; } public string WeekDisplayName { get; set; } = ""; + public long PackageId { get; set; } + public string PackageTitle { get; set; } = ""; public long TotalPoolAmount { get; set; } public int TotalBalances { get; set; } public long ValuePerBalance { get; set; } diff --git a/src/BackOffice/Pages/Commission/WeeklyReports.razor.cs b/src/BackOffice/Pages/Commission/WeeklyReports.razor.cs index d9a8ff1..fb5f12d 100644 --- a/src/BackOffice/Pages/Commission/WeeklyReports.razor.cs +++ b/src/BackOffice/Pages/Commission/WeeklyReports.razor.cs @@ -18,12 +18,13 @@ public partial class WeeklyReports try { var sb = new StringBuilder(); - sb.AppendLine("هفته,مبلغ کل استخر,مجموع موجودی‌ها,ارزش هر موجودی,وضعیت,تاریخ محاسبه"); + sb.AppendLine("هفته,پکیج,مبلغ کل استخر,مجموع موجودی‌ها,ارزش هر موجودی,وضعیت,تاریخ محاسبه"); foreach (var r in _reports) { sb.AppendLine(string.Join(",", EscapeCsv(r.WeekDisplayName), + EscapeCsv(r.PackageTitle), r.TotalPoolAmount, r.TotalBalances, r.ValuePerBalance, diff --git a/src/BackOffice/Pages/Payment/LedgerTransactions.razor b/src/BackOffice/Pages/Payment/LedgerTransactions.razor index 5448f2a..f19cbd7 100644 --- a/src/BackOffice/Pages/Payment/LedgerTransactions.razor +++ b/src/BackOffice/Pages/Payment/LedgerTransactions.razor @@ -96,6 +96,16 @@ + + + @(context.Item.UserId != null ? context.Item.UserId.ToString() : "—") + + + + + @(string.IsNullOrWhiteSpace(context.Item.UserFullName) ? "—" : context.Item.UserFullName) + + @@ -232,13 +242,13 @@ Filter = BuildFilter() }); var sb = new System.Text.StringBuilder(); - sb.AppendLine("Id,Type,Amount,Description,Status,RefId,PaymentDate,Created"); + sb.AppendLine("Id,UserId,UserFullName,Type,Amount,Description,Status,RefId,PaymentDate,Created"); foreach (var r in result.Models) { var type = r.HasType ? ReportLabels.GetTransactionTypeLabel(r.Type) : ""; var status = r.HasPaymentStatus ? ReportLabels.GetTransactionPaymentStatusLabel(r.PaymentStatus) : ""; var paymentDate = r.PaymentDate != null ? r.PaymentDate.ToDateTime().ToString("yyyy-MM-dd HH:mm") : ""; - sb.AppendLine($"{r.Id},{type},{r.Amount},\"{r.Description}\",{status},{r.RefId},{paymentDate},{r.Created.ToDateTime():yyyy-MM-dd HH:mm}"); + sb.AppendLine($"{r.Id},{r.UserId},\"{r.UserFullName}\",{type},{r.Amount},\"{r.Description}\",{status},{r.RefId},{paymentDate},{r.Created.ToDateTime():yyyy-MM-dd HH:mm}"); } await jsRuntime.InvokeVoidAsync("jsSaveAsFile", "ledger-transactions.csv", sb.ToString()); } diff --git a/src/BackOffice/Pages/Payment/Transactions.razor b/src/BackOffice/Pages/Payment/Transactions.razor index f25ecd1..9967301 100644 --- a/src/BackOffice/Pages/Payment/Transactions.razor +++ b/src/BackOffice/Pages/Payment/Transactions.razor @@ -82,6 +82,11 @@ + + + @(string.IsNullOrWhiteSpace(context.Item.UserFullName) ? "—" : context.Item.UserFullName) + + @@ -193,9 +198,9 @@ Filter = BuildFilter() }); var sb = new System.Text.StringBuilder(); - sb.AppendLine("Id,UserId,Mobile,Gateway,Amount,Authority,RefId,Status,OrderId,Created"); + sb.AppendLine("Id,UserId,UserFullName,Mobile,Gateway,Amount,Authority,RefId,Status,OrderId,Created"); foreach (var r in result.Models) - sb.AppendLine($"{r.Id},{r.UserId},{r.Mobile},{r.GatewayProvider},{r.Amount},{r.Authority},{r.RefId},{r.PaymentStatus},{r.OrderId},{r.CreatedAt.ToDateTime():yyyy-MM-dd HH:mm}"); + sb.AppendLine($"{r.Id},{r.UserId},\"{r.UserFullName}\",{r.Mobile},{r.GatewayProvider},{r.Amount},{r.Authority},{r.RefId},{r.PaymentStatus},{r.OrderId},{r.CreatedAt.ToDateTime():yyyy-MM-dd HH:mm}"); await jsRuntime.InvokeVoidAsync("jsSaveAsFile", "payment-transactions.csv", sb.ToString()); } catch (Exception ex) { Snackbar.Add($"خطا در export: {ex.Message}", Severity.Error); } diff --git a/src/BackOffice/Pages/User/InvitationsReportPage.razor b/src/BackOffice/Pages/User/InvitationsReportPage.razor new file mode 100644 index 0000000..ebf2740 --- /dev/null +++ b/src/BackOffice/Pages/User/InvitationsReportPage.razor @@ -0,0 +1,85 @@ +@attribute [Route(RouteConstance.InvitationsReport)] +@using CMSMicroservice.Protobuf.Protos.User +@using BackOffice.Common.BaseComponents +@using DataModel = CMSMicroservice.Protobuf.Protos.User.InvitationReportModel + + + + + + + + + + + + + + + + + + + + + + + + همه + فعال + غیرفعال + + + + + + + گزارش دعوت‌ها (جدیدترین اول) + + + + + + @($"{context.Item.InviterFirstName} {context.Item.InviterLastName}".Trim()) + @context.Item.InviterMobile + + + + + @($"{context.Item.InviteeFirstName} {context.Item.InviteeLastName}".Trim()) + @context.Item.InviteeMobile + + + + + @(context.Item.InviteeRegisteredAt?.ToDateTime().ToLocalTime().ToString("yyyy/MM/dd HH:mm") ?? "—") + + + + + @if (context.Item.InviteeClubActive) + { + فعال + } + else + { + غیرفعال + } + + + + + @(context.Item.InvitedAt?.ToDateTime().ToLocalTime().ToString("yyyy/MM/dd HH:mm") ?? "—") + + + + + + + + موردی یافت نشد + + + + diff --git a/src/BackOffice/Pages/User/InvitationsReportPage.razor.cs b/src/BackOffice/Pages/User/InvitationsReportPage.razor.cs new file mode 100644 index 0000000..fd37548 --- /dev/null +++ b/src/BackOffice/Pages/User/InvitationsReportPage.razor.cs @@ -0,0 +1,74 @@ +using CMSMicroservice.Protobuf.Protos.User; +using BackOffice.Common.BaseComponents; +using Microsoft.AspNetCore.Components; +using MudBlazor; +using DataModel = CMSMicroservice.Protobuf.Protos.User.InvitationReportModel; + +namespace BackOffice.Pages.User; + +public partial class InvitationsReportPage +{ + [Inject] public UserContract.UserContractClient UserContract { get; set; } = default!; + + private MudDataGrid _gridData = default!; + private BasePageComponent _basePage = default!; + private GetInvitationsByFilterRequest _request = new() { Filter = new() }; + private string _clubActiveFilter = string.Empty; + + private async Task> ServerReload(GridState state) + { + _request.Filter ??= new(); + ApplyClubFilter(); + _request.PaginationState ??= new(); + _request.PaginationState.PageNumber = state.Page + 1; + _request.PaginationState.PageSize = state.PageSize; + _request.SortBy = "newest"; + + var result = await UserContract.GetInvitationsByFilterAsync(_request); + if (result?.Models != null && result.Models.Any()) + { + return new GridData + { + Items = result.Models.ToList(), + TotalItems = (int)result.MetaData.TotalCount + }; + } + + return new GridData(); + } + + private void ApplyClubFilter() + { + _request.Filter ??= new(); + if (_clubActiveFilter == "true") + _request.Filter.InviteeClubActive = true; + else if (_clubActiveFilter == "false") + _request.Filter.InviteeClubActive = false; + else + _request.Filter.InviteeClubActive = null; + } + + private void ReLoadData() + { + _ = _gridData.ReloadServerData(); + } + + public async Task OnFilterSubmit() + { + ApplyClubFilter(); + _basePage.IsFiltered = true; + StateHasChanged(); + ReLoadData(); + await Task.CompletedTask; + } + + public async Task OnFilterCleared() + { + _basePage.IsFiltered = false; + _clubActiveFilter = string.Empty; + _request = new() { Filter = new() }; + StateHasChanged(); + ReLoadData(); + await Task.CompletedTask; + } +} diff --git a/src/BackOffice/Shared/NavMenu.razor b/src/BackOffice/Shared/NavMenu.razor index c2c9776..4e825a7 100644 --- a/src/BackOffice/Shared/NavMenu.razor +++ b/src/BackOffice/Shared/NavMenu.razor @@ -185,6 +185,11 @@ Icon="@Icons.Material.Filled.People"> کاربران + + گزارش دعوت‌ها + } @if (CanManageRoles)