docs: add CHANGELOG-2025-12-25 - Chatika flag, DayaLoan fix, BackOffice tree rewrite with org-chart, SP_GetNetworkTree
This commit is contained in:
@@ -0,0 +1,421 @@
|
||||
# 📝 Changelog - ۵ دی ۱۴۰۴ (25 December 2025)
|
||||
|
||||
> **Session**: فلگ فعالسازی چتیکا، اصلاح DayaLoan، بازنویسی صفحه درخت شبکه با org-chart، Stored Procedure برای GetNetworkTree
|
||||
|
||||
---
|
||||
|
||||
## 🎯 خلاصه Session
|
||||
|
||||
این session شامل موارد زیر بود:
|
||||
1. **Chatika Enabled Flag** - اضافه کردن فلگ فعال/غیرفعال برای Worker چتیکا
|
||||
2. **DayaLoanCheckWorker Fix** - جلوگیری از استعلام مجدد مشتریان با قرارداد
|
||||
3. **BackOffice Network Tree Rewrite** - بازنویسی کامل با d3-org-chart
|
||||
4. **Tooltip on Hover** - نمایش اطلاعات کاربر روی hover
|
||||
5. **Week Filter Visual** - تمایز بصری کاربران فعال شده در هفته فیلتر شده
|
||||
6. **Stored Procedure** - SP برای GetNetworkTree جهت بهبود performance
|
||||
|
||||
---
|
||||
|
||||
## ✨ New Features
|
||||
|
||||
### 1. Chatika Enabled Flag ✅
|
||||
|
||||
**نیاز**: قابلیت غیرفعال کردن موقت Worker چتیکا از طریق Config
|
||||
|
||||
**راهحل**: اضافه کردن فلگ `Enabled` در تنظیمات
|
||||
|
||||
**تغییرات در `appsettings.json`**:
|
||||
```json
|
||||
"Chatika": {
|
||||
"Enabled": false, // ← فلگ جدید
|
||||
"BaseUrl": "https://api.chatika.ir",
|
||||
"ApiKey": "..."
|
||||
}
|
||||
```
|
||||
|
||||
**تغییرات در `ChatikaAccountActivationJob.cs`**:
|
||||
```csharp
|
||||
public async Task ExecuteAsync()
|
||||
{
|
||||
// Check if Chatika integration is enabled
|
||||
var isEnabled = _configuration.GetValue<bool>("Chatika:Enabled", false);
|
||||
if (!isEnabled)
|
||||
{
|
||||
_logger.LogDebug("Chatika integration is disabled. Skipping job execution.");
|
||||
return;
|
||||
}
|
||||
|
||||
// ... rest of the job
|
||||
}
|
||||
```
|
||||
|
||||
**فایلهای تغییر یافته**:
|
||||
- `CMSMicroservice.WebApi/appsettings.json`
|
||||
- `CMSMicroservice.Infrastructure/BackgroundJobs/ChatikaAccountActivationJob.cs`
|
||||
|
||||
---
|
||||
|
||||
### 2. DayaLoanCheckWorker - Exclude Existing Contracts ✅
|
||||
|
||||
**مشکل**: Worker استعلام دایا برای مشتریانی که قبلاً قرارداد گرفتهاند مجدداً کال میشد
|
||||
|
||||
**راهحل**: فیلتر کردن کاربرانی که `ContractNumber` دارند
|
||||
|
||||
**کد اضافه شده**:
|
||||
```csharp
|
||||
// Get national codes of users who already have contracts
|
||||
var existingContractNationalCodes = await _dbContext.DayaLoanContracts
|
||||
.Where(c => !c.IsDeleted && !string.IsNullOrEmpty(c.ContractNumber))
|
||||
.Select(c => c.NationalCode)
|
||||
.Distinct()
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
// Filter out users who already have contracts
|
||||
var usersToProcess = eligibleUsers
|
||||
.Where(u => !existingContractNationalCodes.Contains(u.NationalCode))
|
||||
.ToList();
|
||||
|
||||
_logger.LogInformation(
|
||||
"Filtered users: {TotalEligible} eligible, {WithContract} already have contracts, {ToProcess} to process",
|
||||
eligibleUsers.Count,
|
||||
eligibleUsers.Count - usersToProcess.Count,
|
||||
usersToProcess.Count);
|
||||
```
|
||||
|
||||
**فایل**: `CMSMicroservice.WebApi/Workers/DayaLoanCheckWorker.cs`
|
||||
|
||||
---
|
||||
|
||||
### 3. 🌳 BackOffice Network Tree - Complete Rewrite with d3-org-chart ✅
|
||||
|
||||
**نیاز**: استفاده از پلاگین org-chart به جای D3 دستی برای نمایش درخت شبکه در پنل ادمین
|
||||
|
||||
**معماری جدید**:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ NetworkTreeViewer.razor │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ MudToolBar: │ │
|
||||
│ │ [Search] [Week Filter] [Expand] [Collapse] [Export] │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ Navigation History (Breadcrumb) │ │
|
||||
│ │ User 123 → User 456 → User 789 │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ d3-org-chart Container (#admin-org-chart) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────┐ │ │
|
||||
│ │ │ Root │ │ │
|
||||
│ │ └──┬───┘ │ │
|
||||
│ │ ┌───┴───┐ │ │
|
||||
│ │ ┌──┴──┐ ┌──┴──┐ │ │
|
||||
│ │ │Left │ │Right│ │ │
|
||||
│ │ └─────┘ └─────┘ │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ MudDataGrid (Table View) │ │
|
||||
│ │ Mobile | Name | Level | Position | Status | Actions │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**فایلهای جدید**:
|
||||
|
||||
| فایل | توضیح |
|
||||
|------|-------|
|
||||
| `wwwroot/js/admin-org-chart.js` | Wrapper برای d3-org-chart با امکانات ادمین |
|
||||
| `wwwroot/css/admin-org-chart.css` | استایل کارتهای نود با رنگبندی چپ/راست |
|
||||
| `wwwroot/js/d3-org-chart3.js` | کتابخانه d3-org-chart (کپی از FrontOffice) |
|
||||
| `wwwroot/js/d3-flextree.min.js` | Dependency برای org-chart |
|
||||
|
||||
**فایلهای تغییر یافته**:
|
||||
- `NetworkTreeViewer.razor` - بازنویسی کامل
|
||||
- `wwwroot/index.html` - اضافه شدن رفرنسهای JS/CSS
|
||||
|
||||
---
|
||||
|
||||
### 4. 💬 Tooltip on Hover ✅
|
||||
|
||||
**نیاز**: نمایش اطلاعات کامل کاربر هنگام hover روی نود
|
||||
|
||||
**پیادهسازی در `admin-org-chart.js`**:
|
||||
|
||||
```javascript
|
||||
// Tooltip container
|
||||
const tooltip = d3.select('body').append('div')
|
||||
.attr('class', 'admin-org-tooltip')
|
||||
.style('opacity', 0);
|
||||
|
||||
// Node hover events
|
||||
.on('mouseover', function(event, d) {
|
||||
tooltip.transition().duration(200).style('opacity', .95);
|
||||
tooltip.html(`
|
||||
<div class="tooltip-header">${d.data.firstName} ${d.data.lastName}</div>
|
||||
<div class="tooltip-row"><span>📱</span> ${d.data.mobile}</div>
|
||||
<div class="tooltip-row"><span>📊</span> سطح: ${d.data.networkLevel}</div>
|
||||
<div class="tooltip-row"><span>📍</span> ${d.data.legPosition === 1 ? 'چپ' : 'راست'}</div>
|
||||
${d.data.isClubActive ?
|
||||
`<div class="tooltip-row active"><span>✅</span> باشگاه فعال</div>` :
|
||||
`<div class="tooltip-row inactive"><span>❌</span> باشگاه غیرفعال</div>`
|
||||
}
|
||||
${d.data.activationWeekDisplayName ?
|
||||
`<div class="tooltip-row"><span>📅</span> ${d.data.activationWeekDisplayName}</div>` : ''
|
||||
}
|
||||
`)
|
||||
.style('left', (event.pageX + 15) + 'px')
|
||||
.style('top', (event.pageY - 10) + 'px');
|
||||
})
|
||||
```
|
||||
|
||||
**استایل Tooltip**:
|
||||
```css
|
||||
.admin-org-tooltip {
|
||||
position: absolute;
|
||||
background: rgba(33, 33, 33, 0.95);
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||
pointer-events: none;
|
||||
z-index: 10000;
|
||||
direction: rtl;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 🎨 Week Filter Visual Distinction ✅
|
||||
|
||||
**نیاز**: وقتی هفته فیلتر میشه، کاربران فعال شده در اون هفته متمایز باشن
|
||||
|
||||
**پیادهسازی**:
|
||||
|
||||
```javascript
|
||||
// Apply week filter styling
|
||||
applyWeekFilter: function(weekId) {
|
||||
if (!this.chart || !this.chartData) return;
|
||||
|
||||
d3.selectAll('.admin-node-card').each(function() {
|
||||
const nodeData = d3.select(this).datum();
|
||||
if (nodeData && nodeData.data) {
|
||||
if (weekId && nodeData.data.activationWeekDefinitionId !== weekId) {
|
||||
d3.select(this).classed('disabled', true);
|
||||
} else {
|
||||
d3.select(this).classed('disabled', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**استایل**:
|
||||
```css
|
||||
/* کاربرانی که در هفته فیلتر شده فعال نشدن */
|
||||
.admin-node-card.disabled {
|
||||
opacity: 0.35;
|
||||
filter: grayscale(70%);
|
||||
}
|
||||
|
||||
/* کاربران فعال شده در هفته هدف */
|
||||
.admin-node-card:not(.disabled) {
|
||||
animation: target-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes target-glow {
|
||||
0%, 100% { box-shadow: 0 0 5px rgba(76, 175, 80, 0.3); }
|
||||
50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.6); }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. ⚡ Stored Procedure for GetNetworkTree ✅
|
||||
|
||||
**نیاز**: بهبود سرعت لود درخت شبکه + حذف محدودیت عمق
|
||||
|
||||
**Stored Procedure** (`dbbkup/SP_GetNetworkTree.sql`):
|
||||
|
||||
```sql
|
||||
CREATE PROCEDURE [CMS].[GetNetworkTree]
|
||||
@RootUserId BIGINT,
|
||||
@MaxDepth INT = 100,
|
||||
@IsClubActive BIT = NULL,
|
||||
@ActivationWeekDefinitionId BIGINT = NULL
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- CTE برای پیمایش درخت باینری به صورت recursive
|
||||
;WITH NetworkTreeCTE AS (
|
||||
-- Base case: ریشه درخت
|
||||
SELECT
|
||||
u.Id AS UserId,
|
||||
u.Mobile,
|
||||
u.FirstName,
|
||||
u.LastName,
|
||||
u.LegPosition,
|
||||
u.NetworkParentId AS ParentId,
|
||||
0 AS NetworkLevel,
|
||||
u.Created AS UserCreated
|
||||
FROM [CMS].[Users] u
|
||||
WHERE u.Id = @RootUserId AND u.IsDeleted = 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Recursive case: فرزندان
|
||||
SELECT
|
||||
u.Id, u.Mobile, u.FirstName, u.LastName, u.LegPosition,
|
||||
u.NetworkParentId, parent.NetworkLevel + 1, u.Created
|
||||
FROM [CMS].[Users] u
|
||||
INNER JOIN NetworkTreeCTE parent ON u.NetworkParentId = parent.UserId
|
||||
WHERE u.IsDeleted = 0 AND parent.NetworkLevel < @MaxDepth
|
||||
)
|
||||
-- Join با ClubMemberships و WeekDefinitions
|
||||
SELECT
|
||||
t.UserId, t.Mobile, t.FirstName, t.LastName, t.LegPosition,
|
||||
t.ParentId, t.NetworkLevel,
|
||||
cm.ActivatedAt AS ClubActivatedAt,
|
||||
ISNULL(cm.IsActive, 0) AS IsClubActive,
|
||||
wd.Id AS ActivationWeekDefinitionId,
|
||||
wd.DisplayName AS ActivationWeekDisplayName,
|
||||
CASE WHEN @ActivationWeekDefinitionId IS NOT NULL
|
||||
AND wd.Id = @ActivationWeekDefinitionId THEN 1 ELSE 0
|
||||
END AS IsActivatedInTargetWeek,
|
||||
t.UserCreated
|
||||
FROM NetworkTreeCTE t
|
||||
LEFT JOIN [CMS].[ClubMemberships] cm ON cm.UserId = t.UserId AND cm.IsDeleted = 0
|
||||
LEFT JOIN [CMS].[WeekDefinitions] wd ON cm.ActivatedAt >= wd.StartDate
|
||||
AND cm.ActivatedAt < wd.EndDate
|
||||
WHERE (@IsClubActive IS NULL OR ISNULL(cm.IsActive, 0) = @IsClubActive
|
||||
OR t.NetworkLevel = 0)
|
||||
ORDER BY t.NetworkLevel, t.ParentId, t.LegPosition
|
||||
OPTION (MAXRECURSION 0); -- بدون محدودیت recursion
|
||||
END
|
||||
```
|
||||
|
||||
**تغییرات در Application Layer**:
|
||||
|
||||
**فایل جدید**: `NetworkTreeNodeDto.cs`
|
||||
```csharp
|
||||
public class NetworkTreeNodeDto
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public string? Mobile { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public int? LegPosition { get; set; }
|
||||
public long? ParentId { get; set; }
|
||||
public int NetworkLevel { get; set; }
|
||||
public DateTime? ClubActivatedAt { get; set; }
|
||||
public bool IsClubActive { get; set; }
|
||||
public long? ActivationWeekDefinitionId { get; set; }
|
||||
public string? ActivationWeekDisplayName { get; set; }
|
||||
public bool IsActivatedInTargetWeek { get; set; }
|
||||
public DateTimeOffset UserCreated { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**بازنویسی `GetNetworkTreeQueryHandler.cs`**:
|
||||
- استفاده از ADO.NET برای اجرای SP
|
||||
- تبدیل نتیجه flat به ساختار درختی
|
||||
- پشتیبانی از همه پارامترهای فیلتر
|
||||
|
||||
**پکیج جدید**:
|
||||
```xml
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.11" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 فایلهای تغییر یافته
|
||||
|
||||
### CMS Microservice
|
||||
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `WebApi/appsettings.json` | Modified | اضافه شدن `Chatika.Enabled` |
|
||||
| `Infrastructure/BackgroundJobs/ChatikaAccountActivationJob.cs` | Modified | چک فلگ Enabled |
|
||||
| `WebApi/Workers/DayaLoanCheckWorker.cs` | Modified | فیلتر کاربران با قرارداد |
|
||||
| `Application/CMSMicroservice.Application.csproj` | Modified | پکیج Relational |
|
||||
| `Application/Common/Interfaces/IApplicationDbContext.cs` | Modified | اضافه شدن DatabaseFacade |
|
||||
| `Application/NetworkMembershipCQ/Queries/GetNetworkTree/GetNetworkTreeQueryHandler.cs` | **REWRITTEN** | استفاده از SP |
|
||||
| `Application/NetworkMembershipCQ/Queries/GetNetworkTree/NetworkTreeNodeDto.cs` | **NEW** | DTO برای نتیجه SP |
|
||||
|
||||
### BackOffice
|
||||
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `Pages/Network/NetworkTreeViewer.razor` | **REWRITTEN** | استفاده از org-chart |
|
||||
| `wwwroot/index.html` | Modified | رفرنسهای JS/CSS |
|
||||
| `wwwroot/js/admin-org-chart.js` | **NEW** | Wrapper برای org-chart |
|
||||
| `wwwroot/css/admin-org-chart.css` | **NEW** | استایل نودها |
|
||||
| `wwwroot/js/d3-org-chart3.js` | **NEW** | کتابخانه org-chart |
|
||||
| `wwwroot/js/d3-flextree.min.js` | **NEW** | Dependency |
|
||||
|
||||
### SQL Scripts
|
||||
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `dbbkup/SP_GetNetworkTree.sql` | **NEW** | Stored Procedure |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 تنظیمات جدید
|
||||
|
||||
### appsettings.json - Chatika
|
||||
```json
|
||||
{
|
||||
"Chatika": {
|
||||
"Enabled": false, // ← جدید: فعال/غیرفعال کردن Worker
|
||||
"BaseUrl": "https://api.chatika.ir",
|
||||
"ApiKey": "YOUR_API_KEY_HERE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Database Changes
|
||||
|
||||
### اجرای Stored Procedure
|
||||
```bash
|
||||
# اجرای اسکریپت در SQL Server
|
||||
sqlcmd -S <server> -d <database> -i dbbkup/SP_GetNetworkTree.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Build Status
|
||||
|
||||
```bash
|
||||
cd /home/masoud/Apps/project/FourSat/CMS/src
|
||||
dotnet build
|
||||
# Result: Build succeeded. 0 Error(s)
|
||||
|
||||
cd /home/masoud/Apps/project/FourSat/BackOffice/src
|
||||
dotnet build BackOffice/BackOffice.csproj
|
||||
# Result: Build succeeded
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 آمار Session
|
||||
|
||||
| متریک | مقدار |
|
||||
|-------|-------|
|
||||
| فایلهای جدید | 6 |
|
||||
| فایلهای تغییر یافته | 8 |
|
||||
| قابلیتهای جدید | 6 |
|
||||
| خطوط کد اضافه شده | ~800 |
|
||||
| Stored Procedure | 1 |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Changelogs
|
||||
|
||||
- [CHANGELOG-2025-12-23.md](CHANGELOG-2025-12-23.md) - پیادهسازی Worker چتیکا
|
||||
- [CHANGELOG-2025-12-20.md](CHANGELOG-2025-12-20.md) - بهبودات قبلی
|
||||
Reference in New Issue
Block a user