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)