Compare commits

..

99 Commits

Author SHA1 Message Date
a178fcd202 Add logic to count absences on Fridays and Thursdays without leave 2025-12-01 19:37:17 +03:30
9e92d2215f Add institution contract workflow count functionality to admin workflow 2025-12-01 10:53:26 +03:30
c63eb23b22 Handle null API response in employee authorization checks 2025-12-01 10:07:09 +03:30
238926118f Handle additional status code 3 in UID service response for employee authorization checks 2025-11-30 11:09:25 +03:30
c874164ca2 Merge branch 'Feature/InstitutionContract/set-discount' 2025-11-29 20:08:00 +03:30
d2f0ed46ae Refactor discount calculation and response models for institution contracts
- Replace InstitutionContractExtensionPaymentResponse with InstitutionContractDiscountResponse in discount-related methods and endpoints
- Update request and response models to include OneMonthAmount, Obligation, and improved discount fields
- Adjust method signatures and controller actions to use new response types
- Refactor discount calculation logic to support new structure and ensure correct plan updates for both installment and one-time payments
- Improve naming consistency for discount percentage fields
2025-11-29 20:07:29 +03:30
40dd90074b Add discount amount and percentage fields to InstitutionContract entity and database schema 2025-11-29 14:56:45 +03:30
452b0b6277 Refactor institution contract discount calculation to use TotalAmount instead of PaymentAmount 2025-11-29 13:26:04 +03:30
720e998a54 Return null if FirstName is missing in UID service response and improve null checks in GetPersonalInfo 2025-11-29 12:30:12 +03:30
626722e805 Handle null response from UID service in GetPersonalInfo and return appropriate failure message 2025-11-29 11:43:58 +03:30
5e5910e0fd Add [FromBody] attribute to ResetDiscountForCreate endpoint parameter 2025-11-29 11:30:49 +03:30
5d81731512 Add reset discount functionality for institution contract creation and extension 2025-11-29 11:11:34 +03:30
511932fa58 Add discount support for institution contract extensions
- Introduce DiscountPercentage and DiscountAmount fields to contract creation and payment models
- Implement discount calculation logic in repository
- Add SetDiscountForExtension API endpoint and related request/response models
- Update contract creation and extension flows to handle discounts
2025-11-29 09:44:30 +03:30
95891d5bae Handle BuyInstitutionContractInstallment items in invoice processing and add GetIdByInstallmentId method 2025-11-27 21:12:52 +03:30
f3fa76c292 Prevent duplicate financial invoices by checking for existing unpaid invoices before creation 2025-11-27 11:39:03 +03:30
ac6bbc3587 service 2025-11-26 20:15:54 +03:30
947d7590f4 Fix contract validation and authentication checks
Updated authentication checks for LegalParty and RealParty to
prevent null reference exceptions by ensuring existingContractingParty
is not null before invoking unauthentication methods.

Added a validation step to prevent duplicate contracts by checking
for existing records in the repository based on ContractingPartyId,
RepresentativeId, and TypeOfContract.
2025-11-26 19:47:24 +03:30
91403a52a3 Replace VerifySend with SendInstitutionVerificationCode
Replaced the `_smsService.VerifySend` method with the new
asynchronous `_smsService.SendInstitutionVerificationCode`
method. The new method includes additional parameters:
`contractingPartyFullName`, `contractingParty.id`, and
`institutionContract.id`, providing more context for the
verification process. Added `await` to ensure proper
asynchronous execution.
2025-11-26 18:25:26 +03:30
7e80342f80 Merge branch 'master' of https://github.com/syntax24/OriginalGozareshgir 2025-11-26 17:12:02 +03:30
5e92207778 Refactor financial transaction and invoice handling
Refactored and streamlined the handling of financial transactions, invoices, and installment logic in `InstitutionContractApplication` and `InstitutionContractRepository`. Removed redundant code and consolidated logic for creating financial transactions and invoices into a reusable structure.

- Delegated financial transaction and invoice creation to the application layer.
- Simplified installment handling by directly managing installment lists.
- Introduced modular logic for handling installment and full payment scenarios.
- Replaced redundant `FinancialInvoice` and `FinancialInvoiceItem` creation in the repository layer.
- Added logic to retrieve `financialStatement` from the repository when available.
- Improved consistency in handling `invoiceAmount` across payment-related operations.
- Removed unused code for unpaid invoice retrieval and associated logic.
- Added support for creating `CreateContactInfo` objects for institution contracts.

These changes improve code maintainability, readability, and modularity by reducing duplication and ensuring responsibilities are handled at the appropriate layers.
2025-11-26 17:11:53 +03:30
SamSys
29484e9565 changes 2025-11-26 13:50:28 +03:30
ba640494d2 update workshop plan calculation to use latest roll call service status 2025-11-26 12:36:51 +03:30
6974a505b4 Refactor contract logic and improve async handling
Refactored the `InstitutionContractListStatus.PendingForRenewal` logic in `InstitutionContractRepository.cs` to include additional checks for conflicting contracts.

Updated `OnPostShiftDateNew` in `Index.cshtml.cs` to be asynchronous, removed unused code, and added a call to the new `UpdateInstitutionContract` method.

Introduced `UpdateInstitutionContract` to filter contracts by a predefined list of IDs and streamline related entity inclusion.
2025-11-26 11:52:37 +03:30
6d3d599449 add DashboardController to provide client dashboard view with calendar and holiday information 2025-11-25 16:45:36 +03:30
2d28bd1f98 Merge branch 'Feature/InstitutionContract/edit-phone' 2025-11-25 15:30:46 +03:30
75ae3efb65 refactor UidService to improve code formatting and readability 2025-11-25 12:56:21 +03:30
eb53fd67ef update mobile and national code matching logic in temporary client registration and increase UidService timeout 2025-11-25 12:52:49 +03:30
8ec717916c add unauthenticated edit support for contracting party phone and info in institution contracts 2025-11-25 11:40:44 +03:30
64bdbcbd2d update authentication error handling to include status code 3 as unavailable 2025-11-24 19:35:49 +03:30
7e9ba23b97 add Excel export for workshop roll call data with new exporter and view model 2025-11-23 12:52:07 +03:30
SamSys
e6640a1636 remove PitzaAmir(resturan) HasRollCallRecord sekip condition 2025-11-22 19:53:09 +03:30
SamSys
e9665c190b Remove pitzaamir(resturan) costum static checkout Condition 2025-11-22 19:50:48 +03:30
ea3baf14e8 add HttpPost attribute to Create action in ContactUsController 2025-11-22 15:43:19 +03:30
36f104f316 add ContactUsController to handle contact us form submissions 2025-11-22 15:27:49 +03:30
42cae1295f Merge branch 'master' of https://github.com/syntax24/OriginalGozareshgir 2025-11-21 17:34:14 +03:30
95b281c3a4 change pizza amir lateEntry fine 2025-11-21 17:27:15 +03:30
SamSys
c239b094d7 Merge branch 'master' of https://github.com/samsyntax24/OriginalGozareshgir 2025-11-20 15:51:03 +03:30
9e61bd3f55 Merge branch 'master' into Feature/customize-checkout/pizza-amir 2025-11-20 15:21:06 +03:30
7025478417 feat: add dynamic deduction items to customize checkout and temp entities with migration 2025-11-20 15:20:45 +03:30
SamSys
b5ee4f01c7 update BackgroundInstitutionContract 2025-11-20 14:29:03 +03:30
3937cd8a9f feat: add dynamic deduction items for late entry and insurance fines to checkout calculations 2025-11-20 12:58:25 +03:30
SamSys
3ed14bf2bd update block sms method 2025-11-20 11:37:04 +03:30
933dd3d937 Enhance face embedding service notifications and error handling; add new shift date actions and improve UidService timeout 2025-11-20 10:52:29 +03:30
90d7de4901 Increase max length for contact info and names in contract entities; update related migrations and improve SMS service logic 2025-11-19 21:23:28 +03:30
37aa57d773 Refactor repository and remove unused Index files
Refactored `IPersonalContractingPartyRepository` to replace `GetByRegisterId` with `GetByNationalId`. Updated `InstitutionContractApplication` to use the new method and removed duplicate `RegisterId` validation logic.

Removed `Index.cshtml` and `Index.cshtml.cs` files, including all associated HTML, scripts, styles, and backend logic, indicating a deprecation or restructuring of the related functionality.
2025-11-19 19:16:55 +03:30
cce903f2ae Merge remote-tracking branch 'origin/master' 2025-11-19 11:10:33 +03:30
873ad2f41f Adjust institution contract creation flow to ensure entity is saved before invoice generation 2025-11-19 11:09:42 +03:30
2035b6fff8 feat: add dynamic deductions to checkout model and enhance roll call difference calculations 2025-11-19 10:45:40 +03:30
SamSys
d31cf8470f Sms Sttings Update 2025-11-18 19:13:09 +03:30
SamSys
5a34c9a6c9 Merg from Master 2025-11-18 16:06:13 +03:30
SamSys
4eb78996d5 Instan Send Block Sms Completed 2025-11-18 15:59:02 +03:30
SamSys
9d8e40c841 Instant block sms started 2025-11-18 15:14:18 +03:30
SamSys
4ba21db7c7 Instant Send Smms for reminder completed 2025-11-18 15:10:32 +03:30
164388dac3 Update payment redirect logic in Verify method to include callback URL 2025-11-18 12:46:50 +03:30
e81a44dd2f Merge branch 'Feature/FinancialInvoice/Init'
# Conflicts:
#	PersonalContractingParty.Config/PersonalBootstrapper.cs
2025-11-17 20:52:31 +03:30
f238b5af6b Enhance financial invoice handling by adding InvoiceNumber property and increasing DescriptionOption max length; implement SetPendingWorkflow method 2025-11-17 20:51:21 +03:30
SamSys
f5cb6b276e RemoveSetting Completed 2025-11-17 17:35:04 +03:30
ed746cb60a Refactor invoice handling to use TransactionId and add InvoiceNumber property 2025-11-17 17:06:31 +03:30
07b2596a6a Update APK handling and UI: add title length limit, modify download link, and include force update flag 2025-11-17 00:26:19 +03:30
7dce7f5bc8 Merge branch 'Feature/roll-call/camera-api' 2025-11-16 23:32:15 +03:30
7ac078c631 Refactor APK creation methods to reorder parameters and enhance title length limit in the database 2025-11-16 23:31:43 +03:30
265d5f8b22 Enhance Excel download by grouping institution contracts by ContractingPartyId 2025-11-16 22:29:18 +03:30
cf5c9f29cf Enhance APK upload functionality by adding version name and code parameters, and update UI for better user input validation 2025-11-16 22:09:19 +03:30
7448ddc79c Merge branch 'refs/heads/Feature/roll-call/apk-versioning' into Feature/roll-call/camera-api 2025-11-16 22:00:19 +03:30
3f1a6f3387 Merge branch 'refs/heads/master' into Feature/roll-call/camera-api
# Conflicts:
#	ServiceHost/Properties/launchSettings.json
2025-11-16 21:40:33 +03:30
95d4dfe568 feat: add SignalR integration for Face Embedding with client implementation and notification service 2025-11-16 20:30:15 +03:30
SamSys
a481e941c5 Create Reminder Sms 2025-11-16 19:59:25 +03:30
SamSys
58637ab038 SmsSettings frontEnd 2025-11-16 19:07:59 +03:30
SamSys
d10eff3dd5 MontlySms and blockSms Background Task Completed 2025-11-16 17:26:49 +03:30
3258deeb2c Add support for APK versioning with force update functionality and separate APK types 2025-11-16 13:38:24 +03:30
6d3526fb30 Refactor FinancialInvoiceItem constructor for improved readability 2025-11-15 19:16:47 +03:30
SamSys
ed35067ecc CreateTransaction completed 2025-11-15 19:00:39 +03:30
SamSys
488ce6041a ReminderDebtSms COmpleted 2025-11-15 14:47:03 +03:30
SamSys
0f261684e9 change 2025-11-15 12:51:17 +03:30
SamSys
a2c0cf126a add SmsSettings Table 2025-11-15 12:21:18 +03:30
SamSys
09a1d6df38 SmsSettingUpdate 2025-11-13 13:51:42 +03:30
SamSys
39bacdf8d6 SmsSetting domin created 2025-11-13 13:06:32 +03:30
ba2b402c04 Add Financial Invoice Management System
Refactored `FinancialInvoice` to include new properties (`Description`, `PublicId`, `IsActive`) and methods for managing items and statuses. Introduced `FinancialInvoiceItem` for invoice itemization. Updated `PaymentTransaction` to reference `FinancialInvoice`.

Enhanced repository and application layers with CRUD operations, advanced search functionality, and integration with contracts. Updated `CompanyContext` with `DbSet<FinancialInvoices>` and `DbSet<FinancialInvoiceItem>`.

Created new database tables for `FinancialInvoices` and `FinancialInvoiceItem`, and updated relationships with `PaymentTransactions`. Added DTOs for invoice creation, editing, and searching. Registered `IFinancialInvoiceRepository` for dependency injection.
2025-11-13 12:49:30 +03:30
f3470de8b6 Merge branch 'master' into Feature/FinancialInvoice/Init 2025-11-12 21:02:30 +03:30
783fffa0c2 Add Sepehr Payment Gateway integration
- Added `DigitalReceipt` and `Rrn` columns to `PaymentTransactions` table for enhanced payment tracking.
- Introduced `SepehrPaymentGateway` class for API integration, including methods for creating, verifying, and processing payments.
- Updated `PaymentTransaction` class to include `Gateway`, `Rrn`, and `DigitalReceipt` properties.
- Refactored payment workflows in `GeneralController`, `Index.cshtml.cs`, and `FinancialController` to use Sepehr gateway.
- Added new classes (`TokenReq`, `SepehrGatewayPayResponse`, etc.) for handling Sepehr-specific requests and responses.
- Configured Sepehr gateway in `Program.cs` using the `Parbad` library.
- Updated `appsettings.json` and `appsettings.Development.json` to include `SepehrGateWayTerminalId`.
- Added `Parbad.AspNetCore` and `Parbad.Storage.Cache` packages to the project.
- Improved error handling for payment creation and verification processes.
2025-11-12 21:01:54 +03:30
SamSys
dad334a9bd create SendReminderSmsForBackgroundTask methodes 2025-11-12 18:53:52 +03:30
SamSys
193e9f587f institutioncontract task 2025-11-12 15:37:24 +03:30
syntax24
e00c93b23d change launch setting 2025-11-12 15:05:36 +03:30
SamSys
2164aeb5bc error fixed 2025-11-12 13:27:37 +03:30
SamSys
7e08b44d4d fix conflict 2025-11-12 13:10:57 +03:30
SamSys
eec53c8024 fix conflict 2025-11-12 12:44:38 +03:30
SamSys
8c37826367 merge from master 2025-11-12 12:44:13 +03:30
4a8f76c473 Refactor FinancialInvoice class to simplify properties
Removed `SmsCode`, `FinancialStatementId`, and `FinancialStatement` properties, along with their associated methods (`SetFinancialStatement` and `SetNewSmsCode`).

Added a new `InvoiceId` property of type `Guid` to serve as a unique identifier for invoices. Updated the constructor to initialize `InvoiceId` and removed the `SmsCode` initialization logic.

These changes streamline the `FinancialInvoice` class and improve its alignment with application requirements.
2025-11-12 10:20:22 +03:30
3e5520d8a0 merge from master 2025-11-11 19:57:05 +03:30
0b439d0268 Refactor and integrate face embedding API support
Refactored `EmployeeUploadPicture.cshtml.cs` to improve readability, maintainability, and modularity. Introduced `_httpClientFactory` for HTTP requests and added `SendEmbeddingsToApi` for Python API integration. Enhanced employee-related operations, including activation, image handling, and settings management.

Added `IFaceEmbeddingService` interface and implemented it in `FaceEmbeddingService` to manage face embeddings. Integrated with a Python API for generating, refining, deleting, and retrieving embeddings. Included robust error handling and detailed logging.

Improved code structure, reduced duplication, and added comments for better debugging and future development.

Add face embedding integration for employee management

Introduced `IFaceEmbeddingService` and its implementation to manage
face embeddings via a Python API. Integrated embedding generation
into `EmployeeApplication` and `EmployeeUploadPictureModel`,
enabling image uploads, embedding creation, and validation.

Refactored `EmployeeUploadPictureModel` for clarity, adding methods
to handle image processing, API interactions, and employee
activation/deactivation with embedding checks. Enhanced error
handling, logging, and user feedback.

Removed legacy code and updated dependencies to include
`IHttpClientFactory` and `IFaceEmbeddingService`. Added localized
error messages and improved maintainability by streamlining code.
2025-11-11 18:52:35 +03:30
76666b3da7 add pizza amir calculation method 2025-11-08 19:25:14 +03:30
MahanCh
2f15c2d54b fix: update SMS reminder job schedule and clean up code 2025-08-28 12:05:37 +03:30
MahanCh
9d9f0e14d3 add task job 2025-08-09 12:40:31 +03:30
MahanCh
4d45ee36b6 add PaymentTransactionValidatePending.cs file 2025-07-29 16:06:03 +03:30
MahanCh
7ae08fe023 Merge branch 'master' into Feature/BgService/init 2025-07-29 14:15:18 +03:30
MahanCh
117b5df447 change namespace 2025-07-28 16:03:35 +03:30
MahanCh
fee14c65ec add Hangfire Prj 2025-07-28 16:02:51 +03:30
MahanCh
31defcde7e add financialInvoice Module 2025-07-15 13:32:41 +03:30
MahanCh
a4dbb016d2 add financial invoice 2025-07-14 14:32:58 +03:30
194 changed files with 181467 additions and 4171 deletions

View File

@@ -0,0 +1,22 @@
namespace _0_Framework.Application.Enums;
/// <summary>
/// وضعیت تایید قرادا مالی
/// </summary>
public enum InstitutionContractVerificationStatus
{
/// <summary>
/// در انتظار تایید
/// </summary>
PendingForVerify = 0,
/// <summary>
/// در انتظار کارپوشه
/// </summary>
PendingWorkflow = 1,
/// <summary>
/// تایید شده
/// </summary>
Verified = 2
}

View File

@@ -0,0 +1,36 @@
namespace _0_Framework.Application.Enums;
public enum TypeOfSmsSetting
{
/// <summary>
/// پیامک
/// یادآور بدهی ماهیانه قرارداد مالی
/// </summary>
InstitutionContractDebtReminder,
/// <summary>
/// پیامک
/// صورت حساب ماهانه قرارداد مالی
/// </summary>
MonthlyInstitutionContract,
/// <summary>
/// پیامک
/// اعلام مسدودی طرف حساب
/// </summary>
BlockContractingParty,
/// <summary>
/// پیامک
/// هشدار اول
/// </summary>
Warning,
/// <summary>
///پیامک اقدام قضائی
/// </summary>
LegalAction,
}

View File

@@ -0,0 +1,25 @@
using System.Threading.Tasks;
namespace _0_Framework.Application.FaceEmbedding;
/// <summary>
/// سرویس اطلاع‌رسانی تغییرات Face Embedding
/// </summary>
public interface IFaceEmbeddingNotificationService
{
/// <summary>
/// اطلاع‌رسانی ایجاد یا به‌روزرسانی Embedding
/// </summary>
Task NotifyEmbeddingCreatedAsync(long workshopId, long employeeId, string employeeFullName);
/// <summary>
/// اطلاع‌رسانی حذف Embedding
/// </summary>
Task NotifyEmbeddingDeletedAsync(long workshopId, long employeeId);
/// <summary>
/// اطلاع‌رسانی بهبود Embedding
/// </summary>
Task NotifyEmbeddingRefinedAsync(long workshopId, long employeeId);
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace _0_Framework.Application.FaceEmbedding;
public interface IFaceEmbeddingService
{
Task<OperationResult> GenerateEmbeddingsAsync(long employeeId, long workshopId, string employeeFullName, string picture1Path, string picture2Path);
Task<OperationResult> GenerateEmbeddingsFromStreamAsync(long employeeId, long workshopId, string employeeFullName, Stream picture1Stream, Stream picture2Stream);
Task<OperationResult> RefineEmbeddingAsync(long employeeId, long workshopId, float[] embedding, float confidence, Dictionary<string, object> metadata = null);
Task<OperationResult> DeleteEmbeddingAsync(long employeeId, long workshopId);
Task<OperationResult<FaceEmbeddingResponse>> GetEmbeddingAsync(long employeeId, long workshopId);
}
public class FaceEmbeddingResponse
{
public long EmployeeId { get; set; }
public long WorkshopId { get; set; }
public string EmployeeFullName { get; set; }
public float[] Embedding { get; set; }
public float Confidence { get; set; }
public Dictionary<string, object> Metadata { get; set; }
}

View File

@@ -39,7 +39,7 @@ public class AqayePardakhtPaymentGateway:IPaymentGateway
amount = command.Amount,
callback = command.CallBackUrl,
card_number = command.CardNumber,
invoice_id = command.InvoiceId,
invoice_id = command.TransactionId,
mobile = command.Mobile,
email = command.Email??"",
description = command.Description,
@@ -73,7 +73,7 @@ public class AqayePardakhtPaymentGateway:IPaymentGateway
amount = command.Amount,
callback = command.CallBackUrl,
card_number = command.Amount,
invoice_id = command.InvoiceId,
invoice_id = command.TransactionId,
mobile = command.Mobile,
email = command.Email,
description = command.Email,

View File

@@ -49,12 +49,13 @@ public class WalletAmountResponse
public class CreatePaymentGatewayRequest
{
public double Amount { get; set; }
public string TransactionId { get; set; }
public string CallBackUrl { get; set; }
public string InvoiceId { get; set; }
public string CardNumber { get; set; }
public string Mobile { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public long FinancialInvoiceId { get; set; }
public IDictionary<string, object> ExtraData { get; set; }
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
@@ -16,18 +17,18 @@ public class SepehrPaymentGateway:IPaymentGateway
{
_httpClient = httpClient.CreateClient();
_httpClient.BaseAddress = new Uri("https://sepehr.shaparak.ir/Rest/V1/PeymentApi/");
}
public async Task<PaymentGatewayResponse> Create(CreatePaymentGatewayRequest command, CancellationToken cancellationToken = default)
{
command.ExtraData ??= new Dictionary<string, object>();
command.ExtraData.Add("financialInvoiceId", command.FinancialInvoiceId);
var extraData = JsonConvert.SerializeObject(command.ExtraData);
var res = await _httpClient.PostAsJsonAsync("GetToken", new
{
TerminalID = TerminalId,
Amount = command.Amount,
InvoiceID = command.InvoiceId,
InvoiceID = command.TransactionId,
callbackURL = command.CallBackUrl,
payload = extraData
}, cancellationToken: cancellationToken);

View File

@@ -32,6 +32,60 @@ public interface ISmsService
public Task<bool> SendInstitutionVerificationCode(string number, string code, string contractingPartyFullName,
long contractingPartyId, long institutionContractId);
SmsResult TaskReminderSms(string number, string taskCount);
#endregion
#region InstitutionContractSMS
/// <summary>
/// پیامک اهانه جدید
/// </summary>
/// <param name="number"></param>
/// <param name="tamplateId"></param>
/// <param name="fullname"></param>
/// <param name="amount"></param>
/// <param name="code1"></param>
/// <param name="code2"></param>
/// <returns></returns>
Task<(byte status, string message, int messaeId, bool isSucceded)> MonthlyBillNew(string number, int tamplateId, string fullname, string amount, string code1,
string code2);
/// <summary>
/// پیامک ماهانه قدیم
/// </summary>
/// <param name="number"></param>
/// <param name="tamplateId"></param>
/// <param name="fullname"></param>
/// <param name="amount"></param>
/// <param name="id"></param>
/// <param name="aprove"></param>
/// <returns></returns>
Task<(byte status, string message, int messaeId, bool isSucceded)> MonthlyBill(string number, int tamplateId, string fullname, string amount, string id, string aprove);
/// <summary>
/// پیامک مسدودی طرف حساب
/// </summary>
/// <param name="number"></param>
/// <param name="fullname"></param>
/// <param name="amount"></param>
/// <param name="accountType"></param>
/// <param name="id"></param>
/// <param name="aprove"></param>
/// <returns></returns>
Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessage(string number, string fullname, string amount, string accountType, string id, string aprove);
#endregion
#region AlarmMessage
/// <summary>
/// ارسال پیامک های خطا یا اعمال ارسال
/// </summary>
/// <param name="number"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> Alarm(string number, string message);
#endregion
}

View File

@@ -0,0 +1,32 @@
namespace _0_Framework.Application.Sms;
public class SmsResult
{
public SmsResult()
{
IsSuccedded = false;
}
public bool IsSuccedded { get; set; }
public string Message { get; set; }
public byte StatusCode { get; set; }
public int MessageId { get; set; }
public SmsResult Succedded(byte statusCode, string message, int messageId)
{
IsSuccedded = true;
Message = message;
StatusCode = statusCode;
MessageId = messageId;
return this;
}
public SmsResult Failed(byte statusCode, string message, int messageId)
{
IsSuccedded = false;
Message = message;
StatusCode = statusCode;
MessageId = messageId;
return this;
}
}

View File

@@ -0,0 +1,9 @@
namespace _0_Framework.Application.Enums
{
public class CheckoutDynamicDeductionItem
{
public string Name { get; set; }
public int Count { get; set; }
public string Amount { get; set; }
}
}

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using _0_Framework.Application;
using _0_Framework.Application.FaceEmbedding;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Http;
using System.Threading.Tasks;
namespace _0_Framework.Infrastructure;
/// <summary>
/// پیاده‌سازی سرویس ارتباط با API پایتون برای مدیریت Embeddings چهره
/// </summary>
public class FaceEmbeddingService : IFaceEmbeddingService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<FaceEmbeddingService> _logger;
private readonly IFaceEmbeddingNotificationService _notificationService;
private readonly string _apiBaseUrl;
public FaceEmbeddingService(IHttpClientFactory httpClientFactory, ILogger<FaceEmbeddingService> logger,
IFaceEmbeddingNotificationService notificationService = null)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
_notificationService = notificationService;
_apiBaseUrl = "http://localhost:8000";
}
public async Task<OperationResult> GenerateEmbeddingsAsync(long employeeId, long workshopId,
string employeeFullName, string picture1Path, string picture2Path)
{
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_apiBaseUrl);
httpClient.Timeout = TimeSpan.FromSeconds(30);
using var content = new MultipartFormDataContent();
// Add form fields
content.Add(new StringContent(employeeId.ToString()), "employee_id");
content.Add(new StringContent(workshopId.ToString()), "workshop_id");
content.Add(new StringContent(employeeFullName ?? ""), "employee_full_name");
// Add picture files
if (File.Exists(picture1Path))
{
var picture1Bytes = await File.ReadAllBytesAsync(picture1Path);
var picture1Content = new ByteArrayContent(picture1Bytes);
picture1Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
content.Add(picture1Content, "picture1", "1.jpg");
}
else
{
_logger.LogWarning("Picture1 not found at path: {Path}", picture1Path);
return new OperationResult { IsSuccedded = false, Message = "تصویر اول یافت نشد" };
}
if (File.Exists(picture2Path))
{
var picture2Bytes = await File.ReadAllBytesAsync(picture2Path);
var picture2Content = new ByteArrayContent(picture2Bytes);
picture2Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
content.Add(picture2Content, "picture2", "2.jpg");
}
else
{
_logger.LogWarning("Picture2 not found at path: {Path}", picture2Path);
return new OperationResult { IsSuccedded = false, Message = "تصویر دوم یافت نشد" };
}
// Send request to Python API
var response = await httpClient.PostAsync("embeddings", content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
_logger.LogInformation("Embeddings generated successfully for Employee {EmployeeId}, Workshop {WorkshopId}",
employeeId, workshopId);
// ارسال اطلاع‌رسانی به سایر سیستم‌ها
if (_notificationService != null)
{
await _notificationService.NotifyEmbeddingCreatedAsync(workshopId, employeeId, employeeFullName);
}
return new OperationResult
{
IsSuccedded = true,
Message = "Embedding با موفقیت ایجاد شد"
};
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Failed to generate embeddings. Status: {StatusCode}, Error: {Error}",
response.StatusCode, errorContent);
return new OperationResult
{
IsSuccedded = false,
Message = $"خطا در تولید Embedding: {response.StatusCode}"
};
}
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "HTTP error while calling embeddings API for Employee {EmployeeId}", employeeId);
return new OperationResult
{
IsSuccedded = false,
Message = "خطا در ارتباط با سرور Embedding"
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while calling embeddings API for Employee {EmployeeId}", employeeId);
return new OperationResult
{
IsSuccedded = false,
Message = "خطای غیرمنتظره در تولید Embedding"
};
}
}
public async Task<OperationResult> GenerateEmbeddingsFromStreamAsync(long employeeId, long workshopId,
string employeeFullName, Stream picture1Stream, Stream picture2Stream)
{
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_apiBaseUrl);
httpClient.Timeout = TimeSpan.FromSeconds(30);
using var content = new MultipartFormDataContent();
// Add form fields
content.Add(new StringContent(employeeId.ToString()), "employee_id");
content.Add(new StringContent(workshopId.ToString()), "workshop_id");
content.Add(new StringContent(employeeFullName ?? ""), "employee_full_name");
// Add picture streams
var picture1Content = new StreamContent(picture1Stream);
picture1Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
content.Add(picture1Content, "picture1", "1.jpg");
var picture2Content = new StreamContent(picture2Stream);
picture2Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
content.Add(picture2Content, "picture2", "2.jpg");
// Send request to Python API
var response = await httpClient.PostAsync("embeddings", content);
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Embeddings generated successfully from streams for Employee {EmployeeId}", employeeId);
// ارسال اطلاع‌رسانی به سایر سیستم‌ها
if (_notificationService != null)
{
await _notificationService.NotifyEmbeddingCreatedAsync(workshopId, employeeId, employeeFullName);
}
return new OperationResult { IsSuccedded = true, Message = "Embedding با موفقیت ایجاد شد" };
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Failed to generate embeddings from streams. Status: {StatusCode}, Error: {Error}",
response.StatusCode, errorContent);
return new OperationResult
{
IsSuccedded = false,
Message = $"خطا در تولید Embedding: {response.StatusCode}"
};
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while generating embeddings from streams for Employee {EmployeeId}", employeeId);
return new OperationResult
{
IsSuccedded = false,
Message = "خطا در تولید Embedding"
};
}
}
public async Task<OperationResult> RefineEmbeddingAsync(long employeeId, long workshopId, float[] embedding,
float confidence, Dictionary<string, object> metadata = null)
{
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_apiBaseUrl);
httpClient.Timeout = TimeSpan.FromSeconds(30);
var requestBody = new
{
employeeId,
workshopId,
embedding,
confidence,
metadata = metadata ?? new Dictionary<string, object>()
};
var response = await httpClient.PostAsJsonAsync("embeddings/refine", requestBody);
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Embedding refined successfully for Employee {EmployeeId}", employeeId);
// ارسال اطلاع‌رسانی به سایر سیستم‌ها
if (_notificationService != null)
{
await _notificationService.NotifyEmbeddingRefinedAsync(workshopId, employeeId);
}
return new OperationResult { IsSuccedded = true, Message = "Embedding بهبود یافت" };
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Failed to refine embedding. Status: {StatusCode}, Error: {Error}",
response.StatusCode, errorContent);
return new OperationResult
{
IsSuccedded = false,
Message = $"خطا در بهبود Embedding: {response.StatusCode}"
};
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while refining embedding for Employee {EmployeeId}", employeeId);
return new OperationResult
{
IsSuccedded = false,
Message = "خطا در بهبود Embedding"
};
}
}
public async Task<OperationResult> DeleteEmbeddingAsync(long employeeId, long workshopId)
{
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_apiBaseUrl);
httpClient.Timeout = TimeSpan.FromSeconds(30);
var response = await httpClient.DeleteAsync($"embeddings/{workshopId}/{employeeId}");
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Embedding deleted successfully for Employee {EmployeeId}", employeeId);
// ارسال اطلاع‌رسانی به سایر سیستم‌ها
if (_notificationService != null)
{
await _notificationService.NotifyEmbeddingDeletedAsync(workshopId, employeeId);
}
return new OperationResult { IsSuccedded = true, Message = "Embedding حذف شد" };
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Failed to delete embedding. Status: {StatusCode}, Error: {Error}",
response.StatusCode, errorContent);
return new OperationResult
{
IsSuccedded = false,
Message = $"خطا در حذف Embedding: {response.StatusCode}"
};
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while deleting embedding for Employee {EmployeeId}", employeeId);
return new OperationResult
{
IsSuccedded = false,
Message = "خطا در حذف Embedding"
};
}
}
public async Task<OperationResult<FaceEmbeddingResponse>> GetEmbeddingAsync(long employeeId, long workshopId)
{
try
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(_apiBaseUrl);
httpClient.Timeout = TimeSpan.FromSeconds(30);
var response = await httpClient.GetAsync($"embeddings/{workshopId}/{employeeId}");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var embeddingData = JsonSerializer.Deserialize<FaceEmbeddingResponse>(content,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
_logger.LogInformation("Embedding retrieved successfully for Employee {EmployeeId}", employeeId);
return new OperationResult<FaceEmbeddingResponse>
{
IsSuccedded = true,
Message = "Embedding دریافت شد",
Data = embeddingData
};
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Failed to get embedding. Status: {StatusCode}, Error: {Error}",
response.StatusCode, errorContent);
return new OperationResult<FaceEmbeddingResponse>
{
IsSuccedded = false,
Message = $"خطا در دریافت Embedding: {response.StatusCode}"
};
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error while getting embedding for Employee {EmployeeId}", employeeId);
return new OperationResult<FaceEmbeddingResponse>
{
IsSuccedded = false,
Message = "خطا در دریافت Embedding"
};
}
}
}

View File

@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using _0_Framework.Application.FaceEmbedding;
namespace _0_Framework.InfraStructure;
/// <summary>
/// پیاده‌سازی پیش‌فرض (بدون عملیات) برای IFaceEmbeddingNotificationService
/// این کلاس زمانی استفاده می‌شود که SignalR در دسترس نباشد
/// </summary>
public class NullFaceEmbeddingNotificationService : IFaceEmbeddingNotificationService
{
public Task NotifyEmbeddingCreatedAsync(long workshopId, long employeeId, string employeeFullName)
{
// هیچ عملیاتی انجام نمی‌دهد
return Task.CompletedTask;
}
public Task NotifyEmbeddingDeletedAsync(long workshopId, long employeeId)
{
// هیچ عملیاتی انجام نمی‌دهد
return Task.CompletedTask;
}
public Task NotifyEmbeddingRefinedAsync(long workshopId, long employeeId)
{
// هیچ عملیاتی انجام نمی‌دهد
return Task.CompletedTask;
}
}

624
ANDROID_SIGNALR_GUIDE.md Normal file
View File

@@ -0,0 +1,624 @@
# راهنمای اتصال اپلیکیشن Android به SignalR برای Face Embedding
## 1. افزودن کتابخانه SignalR به پروژه Android
در فایل `build.gradle` (Module: app) خود، dependency زیر را اضافه کنید:
```gradle
dependencies {
// SignalR for Android
implementation 'com.microsoft.signalr:signalr:7.0.0'
// اگر از Kotlin استفاده می‌کنید:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
// برای JSON پردازش:
implementation 'com.google.code.gson:gson:2.10.1'
}
```
## 2. اضافه کردن Permission در AndroidManifest.xml
```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```
## 3. کد Java/Kotlin برای اتصال به SignalR
### نسخه Java:
```java
import com.microsoft.signalr.HubConnection;
import com.microsoft.signalr.HubConnectionBuilder;
import com.microsoft.signalr.HubConnectionState;
import com.google.gson.JsonObject;
import android.util.Log;
public class FaceEmbeddingSignalRClient {
private static final String TAG = "FaceEmbeddingHub";
private HubConnection hubConnection;
private String serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub"; // آدرس سرور خود را وارد کنید
private long workshopId;
public FaceEmbeddingSignalRClient(long workshopId) {
this.workshopId = workshopId;
initializeSignalR();
}
private void initializeSignalR() {
// ایجاد اتصال SignalR
hubConnection = HubConnectionBuilder
.create(serverUrl)
.build();
// دریافت رویداد ایجاد Embedding
hubConnection.on("EmbeddingCreated", (data) -> {
JsonObject jsonData = (JsonObject) data;
long employeeId = jsonData.get("employeeId").getAsLong();
String employeeFullName = jsonData.get("employeeFullName").getAsString();
String timestamp = jsonData.get("timestamp").getAsString();
Log.d(TAG, "Embedding Created - Employee: " + employeeFullName + " (ID: " + employeeId + ")");
// اینجا می‌توانید داده‌های جدید را از سرور بگیرید یا UI را بروزرسانی کنید
onEmbeddingCreated(employeeId, employeeFullName, timestamp);
}, JsonObject.class);
// دریافت رویداد حذف Embedding
hubConnection.on("EmbeddingDeleted", (data) -> {
JsonObject jsonData = (JsonObject) data;
long employeeId = jsonData.get("employeeId").getAsLong();
String timestamp = jsonData.get("timestamp").getAsString();
Log.d(TAG, "Embedding Deleted - Employee ID: " + employeeId);
onEmbeddingDeleted(employeeId, timestamp);
}, JsonObject.class);
// دریافت رویداد بهبود Embedding
hubConnection.on("EmbeddingRefined", (data) -> {
JsonObject jsonData = (JsonObject) data;
long employeeId = jsonData.get("employeeId").getAsLong();
String timestamp = jsonData.get("timestamp").getAsString();
Log.d(TAG, "Embedding Refined - Employee ID: " + employeeId);
onEmbeddingRefined(employeeId, timestamp);
}, JsonObject.class);
}
public void connect() {
if (hubConnection.getConnectionState() == HubConnectionState.DISCONNECTED) {
hubConnection.start()
.doOnComplete(() -> {
Log.d(TAG, "Connected to SignalR Hub");
joinWorkshopGroup();
})
.doOnError(error -> {
Log.e(TAG, "Error connecting to SignalR: " + error.getMessage());
})
.subscribe();
}
}
private void joinWorkshopGroup() {
// عضویت در گروه مخصوص این کارگاه
hubConnection.send("JoinWorkshopGroup", workshopId);
Log.d(TAG, "Joined workshop group: " + workshopId);
}
public void disconnect() {
if (hubConnection.getConnectionState() == HubConnectionState.CONNECTED) {
// خروج از گروه
hubConnection.send("LeaveWorkshopGroup", workshopId);
hubConnection.stop();
Log.d(TAG, "Disconnected from SignalR Hub");
}
}
// این متدها را در Activity/Fragment خود override کنید
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
// اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید
}
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
// اینجا UI را بروزرسانی کنید
}
protected void onEmbeddingRefined(long employeeId, String timestamp) {
// اینجا UI را بروزرسانی کنید
}
}
```
### نسخه Kotlin:
```kotlin
import com.microsoft.signalr.HubConnection
import com.microsoft.signalr.HubConnectionBuilder
import com.microsoft.signalr.HubConnectionState
import com.google.gson.JsonObject
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class FaceEmbeddingSignalRClient(private val workshopId: Long) {
companion object {
private const val TAG = "FaceEmbeddingHub"
}
private lateinit var hubConnection: HubConnection
private val serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub" // آدرس سرور خود را وارد کنید
init {
initializeSignalR()
}
private fun initializeSignalR() {
hubConnection = HubConnectionBuilder
.create(serverUrl)
.build()
// دریافت رویداد ایجاد Embedding
hubConnection.on("EmbeddingCreated", { data: JsonObject ->
val employeeId = data.get("employeeId").asLong
val employeeFullName = data.get("employeeFullName").asString
val timestamp = data.get("timestamp").asString
Log.d(TAG, "Embedding Created - Employee: $employeeFullName (ID: $employeeId)")
onEmbeddingCreated(employeeId, employeeFullName, timestamp)
}, JsonObject::class.java)
// دریافت رویداد حذف Embedding
hubConnection.on("EmbeddingDeleted", { data: JsonObject ->
val employeeId = data.get("employeeId").asLong
val timestamp = data.get("timestamp").asString
Log.d(TAG, "Embedding Deleted - Employee ID: $employeeId")
onEmbeddingDeleted(employeeId, timestamp)
}, JsonObject::class.java)
// دریافت رویداد بهبود Embedding
hubConnection.on("EmbeddingRefined", { data: JsonObject ->
val employeeId = data.get("employeeId").asLong
val timestamp = data.get("timestamp").asString
Log.d(TAG, "Embedding Refined - Employee ID: $employeeId")
onEmbeddingRefined(employeeId, timestamp)
}, JsonObject::class.java)
}
fun connect() {
if (hubConnection.connectionState == HubConnectionState.DISCONNECTED) {
CoroutineScope(Dispatchers.IO).launch {
try {
hubConnection.start().blockingAwait()
Log.d(TAG, "Connected to SignalR Hub")
joinWorkshopGroup()
} catch (e: Exception) {
Log.e(TAG, "Error connecting to SignalR: ${e.message}")
}
}
}
}
private fun joinWorkshopGroup() {
hubConnection.send("JoinWorkshopGroup", workshopId)
Log.d(TAG, "Joined workshop group: $workshopId")
}
fun disconnect() {
if (hubConnection.connectionState == HubConnectionState.CONNECTED) {
hubConnection.send("LeaveWorkshopGroup", workshopId)
hubConnection.stop()
Log.d(TAG, "Disconnected from SignalR Hub")
}
}
// این متدها را override کنید
open fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
// اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید
}
open fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
// اینجا UI را بروزرسانی کنید
}
open fun onEmbeddingRefined(employeeId: Long, timestamp: String) {
// اینجا UI را بروزرسانی کنید
}
}
```
## 4. استفاده در Activity یا Fragment
### مثال با Login و دریافت WorkshopId
#### Java:
```java
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button btnLogin = findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(v -> performLogin());
}
private void performLogin() {
// فراخوانی API لاگین
// فرض کنید response شامل workshopId است
// مثال ساده (باید از Retrofit یا کتابخانه مشابه استفاده کنید):
// LoginResponse response = apiService.login(username, password);
// long workshopId = response.getWorkshopId();
long workshopId = 123; // این را از response دریافت کنید
// ذخیره workshopId
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
prefs.edit().putLong("workshopId", workshopId).apply();
// رفتن به صفحه اصلی
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}
public class MainActivity extends AppCompatActivity {
private FaceEmbeddingSignalRClient signalRClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// دریافت workshopId از SharedPreferences
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
long workshopId = prefs.getLong("workshopId", 0);
if (workshopId == 0) {
// اگر workshopId وجود نداره، برگرد به صفحه لاگین
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
return;
}
// ایجاد و اتصال SignalR
signalRClient = new FaceEmbeddingSignalRClient(workshopId) {
@Override
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
runOnUiThread(() -> {
// بروزرسانی UI
Toast.makeText(MainActivity.this,
"Embedding ایجاد شد برای: " + employeeFullName,
Toast.LENGTH_SHORT).show();
// دریافت داده‌های جدید از API
refreshEmployeeList();
});
}
@Override
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
runOnUiThread(() -> {
// بروزرسانی UI
refreshEmployeeList();
});
}
@Override
protected void onEmbeddingRefined(long employeeId, String timestamp) {
runOnUiThread(() -> {
// بروزرسانی UI
refreshEmployeeList();
});
}
};
signalRClient.connect();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (signalRClient != null) {
signalRClient.disconnect();
}
}
private void refreshEmployeeList() {
// دریافت لیست جدید کارمندان از API
}
}
```
#### Kotlin:
```kotlin
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
val btnLogin = findViewById<Button>(R.id.btnLogin)
btnLogin.setOnClickListener { performLogin() }
}
private fun performLogin() {
// فراخوانی API لاگین
// فرض کنید response شامل workshopId است
// مثال ساده (باید از Retrofit یا کتابخانه مشابه استفاده کنید):
// val response = apiService.login(username, password)
// val workshopId = response.workshopId
val workshopId = 123L // این را از response دریافت کنید
// ذخیره workshopId
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
prefs.edit().putLong("workshopId", workshopId).apply()
// رفتن به صفحه اصلی
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
}
class MainActivity : AppCompatActivity() {
private lateinit var signalRClient: FaceEmbeddingSignalRClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// دریافت workshopId از SharedPreferences
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
val workshopId = prefs.getLong("workshopId", 0L)
if (workshopId == 0L) {
// اگر workshopId وجود نداره، برگرد به صفحه لاگین
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
return
}
// ایجاد و اتصال SignalR
signalRClient = object : FaceEmbeddingSignalRClient(workshopId) {
override fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
runOnUiThread {
// بروزرسانی UI
Toast.makeText(this@MainActivity,
"Embedding ایجاد شد برای: $employeeFullName",
Toast.LENGTH_SHORT).show()
// دریافت داده‌های جدید از API
refreshEmployeeList()
}
}
override fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
runOnUiThread {
// بروزرسانی UI
refreshEmployeeList()
}
}
override fun onEmbeddingRefined(employeeId: Long, timestamp: String) {
runOnUiThread {
// بروزرسانی UI
refreshEmployeeList()
}
}
}
signalRClient.connect()
}
override fun onDestroy() {
super.onDestroy()
signalRClient.disconnect()
}
private fun refreshEmployeeList() {
// دریافت لیست جدید کارمندان از API
}
}
```
### مثال ساده بدون Login:
اگر workshopId را از قبل می‌دانید:
#### Java:
```java
public class MainActivity extends AppCompatActivity {
private FaceEmbeddingSignalRClient signalRClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
long workshopId = 123; // شناسه کارگاه خود را وارد کنید
signalRClient = new FaceEmbeddingSignalRClient(workshopId) {
@Override
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
runOnUiThread(() -> {
// بروزرسانی UI
Toast.makeText(MainActivity.this,
"Embedding ایجاد شد برای: " + employeeFullName,
Toast.LENGTH_SHORT).show();
// دریافت داده‌های جدید از API
refreshEmployeeList();
});
}
@Override
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
runOnUiThread(() -> {
// بروزرسانی UI
refreshEmployeeList();
});
}
};
signalRClient.connect();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (signalRClient != null) {
signalRClient.disconnect();
}
}
private void refreshEmployeeList() {
// دریافت لیست جدید کارمندان از API
}
}
```
#### Kotlin:
```kotlin
class MainActivity : AppCompatActivity() {
private lateinit var signalRClient: FaceEmbeddingSignalRClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val workshopId = 123L // شناسه کارگاه خود را وارد کنید
signalRClient = object : FaceEmbeddingSignalRClient(workshopId) {
override fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
runOnUiThread {
// بروزرسانی UI
Toast.makeText(this@MainActivity,
"Embedding ایجاد شد برای: $employeeFullName",
Toast.LENGTH_SHORT).show()
// دریافت داده‌های جدید از API
refreshEmployeeList()
}
}
override fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
runOnUiThread {
// بروزرسانی UI
refreshEmployeeList()
}
}
}
signalRClient.connect()
}
override fun onDestroy() {
super.onDestroy()
signalRClient.disconnect()
}
private fun refreshEmployeeList() {
// دریافت لیست جدید کارمندان از API
}
}
```
## 5. نکات مهم
### آدرس سرور
- اگر روی شبیه‌ساز اندروید تست می‌کنید و سرور روی localhost اجرا می‌شود، از آدرس `http://10.0.2.2:PORT` استفاده کنید
- اگر روی دستگاه فیزیکی تست می‌کنید، از آدرس IP شبکه محلی سرور استفاده کنید (مثل `http://192.168.1.100:PORT`)
- PORT پیش‌فرض معمولاً 5000 یا 5001 است (بسته به کانفیگ پروژه شما)
### دریافت WorkshopId از Login
بعد از login موفق، workshopId را از سرور دریافت کنید و در SharedPreferences یا یک Singleton ذخیره کنید:
```java
// بعد از login موفق
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
prefs.edit().putLong("workshopId", workshopId).apply();
// استفاده در Activity
long workshopId = prefs.getLong("workshopId", 0);
```
یا در Kotlin:
```kotlin
// بعد از login موفق
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
prefs.edit().putLong("workshopId", workshopId).apply()
// استفاده در Activity
val workshopId = prefs.getLong("workshopId", 0L)
```
### مدیریت اتصال
برای reconnection خودکار:
```java
hubConnection.onClosed(exception -> {
Log.e(TAG, "Connection closed. Attempting to reconnect...");
new Handler().postDelayed(() -> connect(), 5000); // تلاش مجدد بعد از 5 ثانیه
});
```
### Thread Safety
همیشه UI updates را در main thread انجام دهید:
```java
runOnUiThread(() -> {
// UI updates here
});
```
## 6. تست اتصال
برای تست می‌توانید:
1. اپلیکیشن را اجرا کنید
2. از طریق Postman یا Swagger یک Embedding ایجاد کنید
3. باید در Logcat پیام "Embedding Created" را ببینید
## 7. خطایابی (Debugging)
برای دیدن جزئیات بیشتر:
```java
hubConnection = HubConnectionBuilder
.create(serverUrl)
.withHttpConnectionOptions(options -> {
options.setLogging(LogLevel.TRACE);
})
.build();
```
---
## خلاصه Endpoints
| نوع رویداد | متد SignalR | پارامترهای دریافتی |
|-----------|-------------|---------------------|
| ایجاد Embedding | `EmbeddingCreated` | workshopId, employeeId, employeeFullName, timestamp |
| حذف Embedding | `EmbeddingDeleted` | workshopId, employeeId, timestamp |
| بهبود Embedding | `EmbeddingRefined` | workshopId, employeeId, timestamp |
| متد ارسالی | پارامتر | توضیحات |
|-----------|---------|---------|
| `JoinWorkshopGroup` | workshopId | عضویت در گروه کارگاه |
| `LeaveWorkshopGroup` | workshopId | خروج از گروه کارگاه |

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>BackgroundInstitutionContract.Task</AssemblyName>
<RootNamespace>BackgroundInstitutionContract.Task</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\0_Framework\0_Framework.csproj" />
<ProjectReference Include="..\..\AccountManagement.Configuration\AccountManagement.Configuration.csproj" />
<ProjectReference Include="..\..\PersonalContractingParty.Config\PersonalContractingParty.Config.csproj" />
<ProjectReference Include="..\..\Query.Bootstrapper\Query.Bootstrapper.csproj" />
<ProjectReference Include="..\..\WorkFlow\Infrastructure\WorkFlow.Infrastructure.Config\WorkFlow.Infrastructure.Config.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,32 @@
using _0_Framework.Application;
namespace BackgroundInstitutionContract.Task
{
public class FileUploader : IFileUploader
{
private readonly IWebHostEnvironment _webHostEnvironment;
public FileUploader(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
public string Upload(IFormFile file, string path)
{
if (file == null) return "";
var directoryPath = $"{_webHostEnvironment.WebRootPath}\\ProductPictures\\{path}";
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
var fileName = $"{DateTime.Now.ToFileName()}-{file.FileName}";
var filePath = $"{directoryPath}\\{fileName}";
var output = System.IO.File.Create(filePath);
file.CopyTo(output);
return $"{path}/{fileName}";
}
}
}

View File

@@ -0,0 +1,149 @@
using _0_Framework.Application;
using Company.Domain.ContarctingPartyAgg;
using Company.Domain.InstitutionContractAgg;
using Hangfire;
namespace BackgroundInstitutionContract.Task.Jobs;
public class JobSchedulerRegistrator
{
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly SmsReminder _smsReminder;
private readonly IInstitutionContractRepository _institutionContractRepository;
private static DateTime? _lastRunCreateTransaction;
private static DateTime? _lastRunSendMonthlySms;
public JobSchedulerRegistrator(SmsReminder smsReminder, IBackgroundJobClient backgroundJobClient, IInstitutionContractRepository institutionContractRepository)
{
_smsReminder = smsReminder;
_backgroundJobClient = backgroundJobClient;
_institutionContractRepository = institutionContractRepository;
}
public void Register()
{
RecurringJob.AddOrUpdate(
"InstitutionContract.CreateFinancialTransaction",
() => CreateFinancialTransaction(),
"*/30 * * * *" // هر 30 دقیقه یکبار چک کن
);
RecurringJob.AddOrUpdate(
"InstitutionContract.SendMonthlySms",
() => SendFirstDayOfMonthSms(),
"*/20 * * * *" // هر 30 دقیقه یکبار چک کن
);
RecurringJob.AddOrUpdate(
"InstitutionContract.SendReminderSms",
() => SendReminderSms(),
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
RecurringJob.AddOrUpdate(
"InstitutionContract.SendBlockSms",
() => SendBlockSms(),
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
}
/// <summary>
/// ایجاد سند بدهی ماهیانه برای قراداد مالی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 1200)]
public async System.Threading.Tasks.Task CreateFinancialTransaction()
{
var now =DateTime.Now;
var endOfMonth = now.ToFarsi().FindeEndOfMonth();
var endOfMonthGr = endOfMonth.ToGeorgianDateTime();
if (now.Date == endOfMonthGr.Date && now.Hour >= 2 && now.Hour < 4 &&
now.Date != _lastRunCreateTransaction?.Date)
{
var month = endOfMonth.Substring(5, 2);
var year = endOfMonth.Substring(0, 4);
var monthName = month.ToFarsiMonthByNumber();
var description = $"{monthName} {year}";
var endnew = ($"{endOfMonth.Substring(0, 8)}01").FindeEndOfMonth();
var endNewGr = endnew.ToGeorgianDateTime();
var endNewFa = endNewGr.ToFarsi();
try
{
await _institutionContractRepository.CreateTransactionForInstitutionContracts(endNewGr, endNewFa, description);
_lastRunCreateTransaction = now;
Console.WriteLine("CreateTransAction executed");
}
catch (Exception e)
{
//_smsService.Alarm("09114221321", "خطا-ایجاد سند مالی");
}
}
}
/// <summary>
/// ارسال پیامک صورت حساب ماهانه
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 600)]
public async System.Threading.Tasks.Task SendFirstDayOfMonthSms()
{
//var now = new DateTime(2025,11,21, 10,30,0);
var now = DateTime.Now;
var endOfMonth = now.ToFarsi().FindeEndOfMonth();
var endOfMonthGr = endOfMonth.ToGeorgianDateTime();
if (now.Date == endOfMonthGr.Date && now.Hour >= 10 && now.Hour < 11 &&
now.Date != _lastRunSendMonthlySms?.Date)
{
try
{
await _institutionContractRepository.SendMonthlySms(now);
_lastRunSendMonthlySms = now;
Console.WriteLine("Send Monthly sms executed");
}
catch (Exception e)
{
//_smsService.Alarm("09114221321", "خطا-ایجاد سند مالی");
}
}
}
/// <summary>
/// ارسال پیامک یاد آور بدهی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 1200)]
public async System.Threading.Tasks.Task SendReminderSms()
{
await _institutionContractRepository.SendReminderSmsForBackgroundTask();
}
/// <summary>
/// ارسال پیامک مسدودی
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task SendBlockSms()
{
await _institutionContractRepository.SendBlockSmsForBackgroundTask();
}
}

View File

@@ -0,0 +1,116 @@
using _0_Framework.Application.Sms;
using AccountManagement.Application.Contracts.Account;
using AccountMangement.Infrastructure.EFCore;
using Company.Domain.SmsResultAgg;
using Microsoft.EntityFrameworkCore;
using SmsResult = Company.Domain.SmsResultAgg.SmsResult;
namespace BackgroundInstitutionContract.Task.Jobs;
public class SmsReminder
{
private readonly AccountContext _accountContext;
private readonly ISmsService _smsService;
private readonly ISmsResultRepository _smsResultRepository;
public SmsReminder(ISmsService smsService, AccountContext accountContext, ISmsResultRepository smsResultRepository)
{
_smsService = smsService;
_accountContext = accountContext;
_smsResultRepository = smsResultRepository;
}
public void Execute()
{
//var accounts = _accountContext.Accounts.Where(x => x.PositionId > 0 && x.IsActiveString == "true").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
//Thread.Sleep(300);
//var accounts = new List<AccountViewModel>() { new AccountViewModel() { Mobile = "09114221321", Id = 2 } };
var accounts= _accountContext.Accounts.Where(x => x.Username.ToLower()=="mahan").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
var smsVM = accounts.Select(x => new AccountSmsTaskViewModel()
{
Mobile = x.Mobile,
AccountId = x.Id,
FullName = x.Fullname,
TaskCount = GetLateTasksCount(x.Id)
}).Where(x => x.TaskCount > 0 && !string.IsNullOrEmpty(x.Mobile) && x.Mobile.Length == 11).ToList();
Thread.Sleep(300);
foreach (var viewmodel in smsVM)
{
var smsResult = _smsService.TaskReminderSms(viewmodel.Mobile, $"{viewmodel.TaskCount}");
Thread.Sleep(1000);
var createSmsResult = new SmsResult(smsResult.MessageId, smsResult.Message, "یادآور وظایف",
viewmodel.FullName, viewmodel.Mobile, viewmodel.AccountId, viewmodel.AccountId);
_smsResultRepository.Create(createSmsResult);
_smsResultRepository.SaveChanges();
Thread.Sleep(1000);
}
}
private int GetLateTasksCount(long accountId)
{
var positionValue = _accountContext.Accounts
.Where(x => x.id == accountId)
.Include(p => p.Position)
.Select(x => x.Position.PositionValue)
.FirstOrDefault();
if (positionValue == 0)
return 0;
DateTime now = DateTime.Now;
int overdueTasksCount;
if (positionValue == 1)
{
overdueTasksCount = _accountContext.Assigns.Include(x => x.Task).Where(x => x.AssignedId == accountId &&
x.AssignerId == accountId && x.Task.Assigns.Count == 1 &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId && a.AssignerId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId && a.AssignerId == accountId)
// .EndTaskDate.Date <= DateTime.Now.Date) && x.Assigns.Count == 1);
}
else
{
overdueTasksCount = _accountContext.Assigns
.Include(x => x.Task)
.Where(x => x.AssignedId == accountId &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
}
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId).EndTaskDate.Date <= DateTime.Now.Date));
var overdueRequestsCount = _accountContext.Assigns.Include(x => x.Task)
.Where(x => (x.IsCanceledRequest
|| x.IsDoneRequest || x.TimeRequest) && !x.IsCancel && !x.IsDone &&
x.Task.IsActiveString == "true" &&
x.Task.SenderId == accountId).GroupBy(x => x.TaskId).Select(x => x.First()).Count();
return overdueTasksCount + overdueRequestsCount;
}
}
public class AccountSmsTaskViewModel
{
public int TaskCount { get; set; }
public long AccountId { get; set; }
public string Mobile { get; set; }
public string FullName { get; set; }
}

View File

@@ -0,0 +1,25 @@
using BackgroundInstitutionContract.Task.Jobs;
namespace BackgroundInstitutionContract.Task;
public class JobsBootstrapper
{
public static void Configure(IServiceCollection services)
{
var currentNamespace = typeof(JobSchedulerRegistrator).Namespace; // همون namespace کلاس
var assembly = typeof(JobSchedulerRegistrator).Assembly;
var jobTypes = assembly.GetTypes()
.Where(t =>
t is { IsClass: true, IsAbstract: false, Namespace: not null } &&
t.Namespace.StartsWith(currentNamespace, StringComparison.Ordinal))
.ToList();
foreach (var jobType in jobTypes)
{
services.AddTransient(jobType);
}
}
}

View File

@@ -0,0 +1,63 @@
using _0_Framework.Application;
using _0_Framework.Application.Sms;
using _0_Framework.Application.UID;
using _0_Framework.InfraStructure.Mongo;
using AccountManagement.Configuration;
using BackgroundInstitutionContract.Task;
using BackgroundInstitutionContract.Task.Jobs;
using CompanyManagment.App.Contracts.Hubs;
using CompanyManagment.EFCore.Services;
using Hangfire;
using Microsoft.AspNetCore.Identity;
using MongoDB.Driver;
using PersonalContractingParty.Config;
using Query.Bootstrapper;
using WorkFlow.Infrastructure.Config;
var builder = WebApplication.CreateBuilder(args);
var hangfireConnectionString = builder.Configuration.GetConnectionString("HangfireDb");
builder.Services.AddHangfire(x => x.UseSqlServerStorage(hangfireConnectionString));
builder.Services.AddHangfireServer();
var connectionString = builder.Configuration.GetConnectionString("MesbahDb");
var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb");
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
builder.Services.AddTransient<IAuthHelper, AuthHelper>();
builder.Services.AddTransient<ISmsService, SmsService>();
builder.Services.AddTransient<IUidService, UidService>();
builder.Services.AddTransient<IFileUploader, FileUploader>();
builder.Services.Configure<AppSettingConfiguration>(builder.Configuration);
#region MongoDb
var mongoConnectionSection = builder.Configuration.GetSection("MongoDb");
var mongoDbSettings = mongoConnectionSection.Get<MongoDbConfig>();
var mongoClient = new MongoClient(mongoDbSettings.ConnectionString);
var mongoDatabase = mongoClient.GetDatabase(mongoDbSettings.DatabaseName);
builder.Services.AddSingleton<IMongoDatabase>(mongoDatabase);
#endregion
PersonalBootstrapper.Configure(builder.Services, connectionString);
TestDbBootStrapper.Configure(builder.Services, connectionStringTestDb);
AccountManagementBootstrapper.Configure(builder.Services, connectionString);
WorkFlowBootstrapper.Configure(builder.Services, connectionString);
QueryBootstrapper.Configure(builder.Services);
JobsBootstrapper.Configure(builder.Services);
builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapHub<SendSmsHub>("/sendSmsHub");
app.MapHangfireDashboard();
app.MapGet("/", () => "Hello World!");
using (var scope = app.Services.CreateScope())
{
var jobScheduler = scope.ServiceProvider.GetRequiredService<JobSchedulerRegistrator>();
jobScheduler.Register();
}
app.Run();

View File

@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56492",
"sslPort": 44378
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7223;http://localhost:5217",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,47 @@
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
//تست
//"MesbahDb": "Data Source=DESKTOP-NUE119G\\MSNEW;Initial Catalog=Mesbah_db;Integrated Security=True"
//server
//"MesbahDb": "Data Source=171.22.24.15;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
//local
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
//dad-mehr
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
//mahan Docker
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;",
//"HangfireDb": "Data Source=.;Initial Catalog=hangfire_db;Integrated Security=True;TrustServerCertificate=true;",
"HangfireDb": "Data Source=185.208.175.186;Initial Catalog=hangfire_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;"
},
"GoogleRecaptchaV3": {
"SiteKey": "6Lfhp_AnAAAAAB79WkrMoHd1k8ir4m8VvfjE7FTH",
"SecretKey": "6Lfhp_AnAAAAANjDDY6DPrbbUQS7k6ZCRmrVP5Lb"
},
"SmsSecrets": {
"ApiKey": "Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa",
"SecretKey": "dadmehr"
},
"Domain": ".gozareshgir.ir",
"MongoDb": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "Gozareshgir"
}
}

View File

@@ -0,0 +1,28 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
//local
//"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
"MesbahDb": "Data Source=185.208.175.186;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
//dad-mehr
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
//"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=185.208.175.186;Initial Catalog=TestDb;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
//"MesbahDb": "Data Source=.\\MSSQLSERVER2019;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=mesbah_db;Password=sa142857$@;"
//"HangfireDb": "Data Source=.;Initial Catalog=hangfire_db;Integrated Security=True;TrustServerCertificate=true;",
"HangfireDb": "Data Source=185.208.175.186;Initial Catalog=hangfire_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;"
},
"MongoDb": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "Gozareshgir"
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\0_Framework\0_Framework.csproj" />
<ProjectReference Include="..\..\AccountManagement.Configuration\AccountManagement.Configuration.csproj" />
<ProjectReference Include="..\..\PersonalContractingParty.Config\PersonalContractingParty.Config.csproj" />
<ProjectReference Include="..\..\Query.Bootstrapper\Query.Bootstrapper.csproj" />
<ProjectReference Include="..\..\WorkFlow\Infrastructure\WorkFlow.Infrastructure.Config\WorkFlow.Infrastructure.Config.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,32 @@
using _0_Framework.Application;
namespace BackgroundJobs.Task
{
public class FileUploader : IFileUploader
{
private readonly IWebHostEnvironment _webHostEnvironment;
public FileUploader(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
public string Upload(IFormFile file, string path)
{
if (file == null) return "";
var directoryPath = $"{_webHostEnvironment.WebRootPath}\\ProductPictures\\{path}";
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
var fileName = $"{DateTime.Now.ToFileName()}-{file.FileName}";
var filePath = $"{directoryPath}\\{fileName}";
var output = System.IO.File.Create(filePath);
file.CopyTo(output);
return $"{path}/{fileName}";
}
}
}

View File

@@ -0,0 +1,62 @@
using Hangfire;
namespace BackgroundJobs.Task.Jobs;
public class JobSchedulerRegistrator
{
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly SmsReminder _smsReminder;
private static DateTime? _lastRunDateMorning;
private static DateTime? _lastRunDateEvening;
public JobSchedulerRegistrator(SmsReminder smsReminder, IBackgroundJobClient backgroundJobClient)
{
_smsReminder = smsReminder;
_backgroundJobClient = backgroundJobClient;
}
public void Register()
{
RecurringJob.AddOrUpdate(
"Task.SmsReminderChecker",
() => SmsReminderCheckAndSchedule(),
"*/5 * * * *" // هر 5 دقیقه یکبار چک کن
);
}
public void SmsReminderCheckAndSchedule()
{
var now = DateTime.Now;
var startMorning = new TimeSpan(9, 0, 0);
var endMorning = new TimeSpan(9, 40, 0);
var startEvening = new TimeSpan(15, 30, 0);
var endEvening = new TimeSpan(15, 40, 0);
// صبح
if (now.DayOfWeek != DayOfWeek.Friday &&
now.TimeOfDay >= startMorning &&
now.TimeOfDay < endMorning)
{
if (_lastRunDateMorning?.Date != now.Date)
{
_backgroundJobClient.Enqueue(() => _smsReminder.Execute());
_lastRunDateMorning = now;
}
}
// عصر - پنجشنبه و جمعه تعطیل است
if (now.DayOfWeek != DayOfWeek.Friday &&
now.DayOfWeek != DayOfWeek.Thursday &&
now.TimeOfDay >= startEvening &&
now.TimeOfDay < endEvening)
{
if (_lastRunDateEvening?.Date != now.Date)
{
_backgroundJobClient.Enqueue(() => _smsReminder.Execute());
_lastRunDateEvening = now;
}
}
}
}

View File

@@ -0,0 +1,116 @@
using _0_Framework.Application.Sms;
using AccountManagement.Application.Contracts.Account;
using AccountMangement.Infrastructure.EFCore;
using Company.Domain.SmsResultAgg;
using Microsoft.EntityFrameworkCore;
using SmsResult = Company.Domain.SmsResultAgg.SmsResult;
namespace BackgroundJobs.Task.Jobs;
public class SmsReminder
{
private readonly AccountContext _accountContext;
private readonly ISmsService _smsService;
private readonly ISmsResultRepository _smsResultRepository;
public SmsReminder(ISmsService smsService, AccountContext accountContext, ISmsResultRepository smsResultRepository)
{
_smsService = smsService;
_accountContext = accountContext;
_smsResultRepository = smsResultRepository;
}
public void Execute()
{
//var accounts = _accountContext.Accounts.Where(x => x.PositionId > 0 && x.IsActiveString == "true").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
//Thread.Sleep(300);
//var accounts = new List<AccountViewModel>() { new AccountViewModel() { Mobile = "09114221321", Id = 2 } };
var accounts= _accountContext.Accounts.Where(x => x.Username.ToLower()=="mahan").Select(x => new AccountViewModel() { Id = x.id, Mobile = x.Mobile, Fullname = x.Fullname }).ToList();
var smsVM = accounts.Select(x => new AccountSmsTaskViewModel()
{
Mobile = x.Mobile,
AccountId = x.Id,
FullName = x.Fullname,
TaskCount = GetLateTasksCount(x.Id)
}).Where(x => x.TaskCount > 0 && !string.IsNullOrEmpty(x.Mobile) && x.Mobile.Length == 11).ToList();
Thread.Sleep(300);
foreach (var viewmodel in smsVM)
{
var smsResult = _smsService.TaskReminderSms(viewmodel.Mobile, $"{viewmodel.TaskCount}");
Thread.Sleep(1000);
var createSmsResult = new SmsResult(smsResult.MessageId, smsResult.Message, "یادآور وظایف",
viewmodel.FullName, viewmodel.Mobile, viewmodel.AccountId, viewmodel.AccountId);
_smsResultRepository.Create(createSmsResult);
_smsResultRepository.SaveChanges();
Thread.Sleep(1000);
}
}
private int GetLateTasksCount(long accountId)
{
var positionValue = _accountContext.Accounts
.Where(x => x.id == accountId)
.Include(p => p.Position)
.Select(x => x.Position.PositionValue)
.FirstOrDefault();
if (positionValue == 0)
return 0;
DateTime now = DateTime.Now;
int overdueTasksCount;
if (positionValue == 1)
{
overdueTasksCount = _accountContext.Assigns.Include(x => x.Task).Where(x => x.AssignedId == accountId &&
x.AssignerId == accountId && x.Task.Assigns.Count == 1 &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId && a.AssignerId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId && a.AssignerId == accountId)
// .EndTaskDate.Date <= DateTime.Now.Date) && x.Assigns.Count == 1);
}
else
{
overdueTasksCount = _accountContext.Assigns
.Include(x => x.Task)
.Where(x => x.AssignedId == accountId &&
!x.IsCancel && !x.IsCanceledRequest &&
!x.IsDone && !x.TimeRequest && !x.IsDoneRequest && x.EndTaskDate.Date <= DateTime.Now.Date && x.Task.IsActiveString == "true")
.GroupBy(x => x.TaskId).Select(x => x.First()).Count();
}
//overdueTasksCount = _accountContext.Tasks.Include(x =>
// x.Assigns).Count(x => !x.Assigns.Any(a => a.IsCancel) && !x.Assigns.Any(a => a.IsCanceledRequest) &&
// !x.Assigns.Any(a => a.IsDone) && !x.Assigns.Any(a => a.IsDoneRequest) &&
// !x.Assigns.Any(a => a.TimeRequest)
// && x.Assigns.Any(a => a.AssignedId == accountId) &&
// (x.Assigns.First(a => a.AssignedId == accountId).EndTaskDate.Date <= DateTime.Now.Date));
var overdueRequestsCount = _accountContext.Assigns.Include(x => x.Task)
.Where(x => (x.IsCanceledRequest
|| x.IsDoneRequest || x.TimeRequest) && !x.IsCancel && !x.IsDone &&
x.Task.IsActiveString == "true" &&
x.Task.SenderId == accountId).GroupBy(x => x.TaskId).Select(x => x.First()).Count();
return overdueTasksCount + overdueRequestsCount;
}
}
public class AccountSmsTaskViewModel
{
public int TaskCount { get; set; }
public long AccountId { get; set; }
public string Mobile { get; set; }
public string FullName { get; set; }
}

View File

@@ -0,0 +1,24 @@
using BackgroundJobs.Task.Jobs;
namespace BackgroundJobs.Task;
public class JobsBootstrapper
{
public static void Configure(IServiceCollection services)
{
var currentNamespace = typeof(JobSchedulerRegistrator).Namespace; // همون namespace کلاس
var assembly = typeof(JobSchedulerRegistrator).Assembly;
var jobTypes = assembly.GetTypes()
.Where(t =>
t is { IsClass: true, IsAbstract: false, Namespace: not null } &&
t.Namespace.StartsWith(currentNamespace, StringComparison.Ordinal))
.ToList();
foreach (var jobType in jobTypes)
{
services.AddTransient(jobType);
}
}
}

View File

@@ -0,0 +1,59 @@
using _0_Framework.Application;
using _0_Framework.Application.Sms;
using _0_Framework.Application.UID;
using _0_Framework.InfraStructure.Mongo;
using AccountManagement.Configuration;
using BackgroundJobs.Task;
using BackgroundJobs.Task.Jobs;
using CompanyManagment.EFCore.Services;
using Hangfire;
using Microsoft.AspNetCore.Identity;
using MongoDB.Driver;
using PersonalContractingParty.Config;
using Query.Bootstrapper;
using WorkFlow.Infrastructure.Config;
var builder = WebApplication.CreateBuilder(args);
var hangfireConnectionString = builder.Configuration.GetConnectionString("HangfireDb");
builder.Services.AddHangfire(x => x.UseSqlServerStorage(hangfireConnectionString));
builder.Services.AddHangfireServer();
var connectionString = builder.Configuration.GetConnectionString("MesbahDb");
var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb");
builder.Services.AddSingleton<IPasswordHasher, PasswordHasher>();
builder.Services.AddTransient<IAuthHelper, AuthHelper>();
builder.Services.AddTransient<ISmsService, SmsService>();
builder.Services.AddTransient<IUidService, UidService>();
builder.Services.AddTransient<IFileUploader, FileUploader>();
builder.Services.Configure<AppSettingConfiguration>(builder.Configuration);
#region MongoDb
var mongoConnectionSection = builder.Configuration.GetSection("MongoDb");
var mongoDbSettings = mongoConnectionSection.Get<MongoDbConfig>();
var mongoClient = new MongoClient(mongoDbSettings.ConnectionString);
var mongoDatabase = mongoClient.GetDatabase(mongoDbSettings.DatabaseName);
builder.Services.AddSingleton<IMongoDatabase>(mongoDatabase);
#endregion
PersonalBootstrapper.Configure(builder.Services, connectionString);
TestDbBootStrapper.Configure(builder.Services, connectionStringTestDb);
AccountManagementBootstrapper.Configure(builder.Services, connectionString);
WorkFlowBootstrapper.Configure(builder.Services, connectionString);
QueryBootstrapper.Configure(builder.Services);
JobsBootstrapper.Configure(builder.Services);
builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
app.MapHangfireDashboard();
app.MapGet("/", () => "Hello World!");
using (var scope = app.Services.CreateScope())
{
var jobScheduler = scope.ServiceProvider.GetRequiredService<JobSchedulerRegistrator>();
jobScheduler.Register();
}
app.Run();

View File

@@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56492",
"sslPort": 44378
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7222;http://localhost:5216",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,46 @@
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
//تست
//"MesbahDb": "Data Source=DESKTOP-NUE119G\\MSNEW;Initial Catalog=Mesbah_db;Integrated Security=True"
//server
//"MesbahDb": "Data Source=171.22.24.15;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
//local
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
//dad-mehr
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
//mahan Docker
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;",
"HangfireDb": "Data Source=.;Initial Catalog=hangfire_db;Integrated Security=True;TrustServerCertificate=true;"
},
"GoogleRecaptchaV3": {
"SiteKey": "6Lfhp_AnAAAAAB79WkrMoHd1k8ir4m8VvfjE7FTH",
"SecretKey": "6Lfhp_AnAAAAANjDDY6DPrbbUQS7k6ZCRmrVP5Lb"
},
"SmsSecrets": {
"ApiKey": "Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa",
"SecretKey": "dadmehr"
},
"Domain": ".gozareshgir.ir",
"MongoDb": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "Gozareshgir"
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -1,6 +1,7 @@
using System;
using _0_Framework.Application;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.AndroidApkVersion;
namespace Company.Domain.AndroidApkVersionAgg;
@@ -8,14 +9,17 @@ public class AndroidApkVersion:EntityBase
{
private AndroidApkVersion () { }
public AndroidApkVersion( string versionName,string versionCode, IsActive isActive, string path)
public AndroidApkVersion( string versionName,string versionCode, IsActive isActive, string path, ApkType apkType, bool isForce = false)
{
VersionName = versionName;
VersionCode = versionCode;
IsActive = isActive;
Path = path;
Title = $"Gozareshgir-{versionName}-{CreationDate:g}";
ApkType = apkType;
IsForce = isForce;
var appName = apkType == ApkType.WebView ? "Gozareshgir-WebView" : "Gozareshgir-FaceDetection";
Title = $"{appName}-{versionName}-{CreationDate:g}";
}
public string Title { get; private set; }
@@ -23,6 +27,9 @@ public class AndroidApkVersion:EntityBase
public string VersionCode{ get; private set; }
public IsActive IsActive { get; private set; }
public string Path { get; set; }
public ApkType ApkType { get; private set; }
public bool IsForce { get; private set; }
public void Active()
{
@@ -33,4 +40,4 @@ public class AndroidApkVersion:EntityBase
{
IsActive = IsActive.False;
}
}
}

View File

@@ -1,12 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using _0_Framework_b.Domain;
using CompanyManagment.App.Contracts.AndroidApkVersion;
namespace Company.Domain.AndroidApkVersionAgg;
public interface IAndroidApkVersionRepository:IRepository<long,AndroidApkVersion>
{
IQueryable<AndroidApkVersion> GetActives();
IQueryable<AndroidApkVersion> GetActives(ApkType apkType);
AndroidApkVersion GetLatestActive(ApkType apkType);
void Remove(AndroidApkVersion entity);
System.Threading.Tasks.Task<string> GetLatestActiveVersionPath();
System.Threading.Tasks.Task<string> GetLatestActiveVersionPath(ApkType apkType);
}

View File

@@ -75,5 +75,5 @@ public interface IPersonalContractingPartyRepository :IRepository<long, Personal
Task<GetLegalContractingPartyDetailsViewModel> GetLegalDetails(long id);
Task<PersonalContractingParty> GetByNationalCode(string nationalCode);
Task<PersonalContractingParty> GetByRegisterId(string registerId);
Task<PersonalContractingParty> GetByNationalId(string registerId);
}

View File

@@ -251,6 +251,35 @@ public class PersonalContractingParty : EntityBase
this.IsAuthenticated = true;
Phone = phone;
}
public void UnAuthenticateRealEdit(string fName, string lName, string fatherName,string idNumber,
string idNumberSeri, string idNumberSerial, string dateOfBirth, Gender gender,string phone)
{
this.FName = fName;
this.LName = lName;
this.FatherName = fatherName;
this.IdNumberSeri = idNumberSeri;
this.IdNumberSerial = idNumberSerial;
this.DateOfBirth = !string.IsNullOrWhiteSpace(dateOfBirth) ? dateOfBirth.ToGeorgianDateTime() : null;
this.IdNumber = idNumber;
this.Gender = gender;
Phone = phone;
}
public void UnAuthenticateLegalEdit(string fName, string lName, string fatherName, string idNumber,
string idNumberSeri,
string idNumberSerial, string dateOfBirth, Gender gender, string phone)
{
CeoFName = fName;
CeoLName = lName;
this.FatherName = fatherName;
this.IdNumberSeri = idNumberSeri;
this.IdNumberSerial = idNumberSerial;
this.DateOfBirth = !string.IsNullOrWhiteSpace(dateOfBirth) ? dateOfBirth.ToGeorgianDateTime() : null;
this.IdNumber = idNumber;
this.Gender = gender;
Phone = phone;
}
public void RegisterComplete(string fatherName, string idNumberSeri, string idNumberSerial, DateTime dateOfBirth, Gender gender)
{

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.ValueObjects;
@@ -33,7 +34,8 @@ public class CustomizeCheckout : EntityBase
ICollection<CustomizeCheckoutSalaryAid> customizeCheckoutSalaryAids,
ICollection<CustomizeCheckoutReward> customizeCheckoutRewards, TimeSpan lateToWorkValue, double settingSalary,
double dailyWage, WorkshopShiftStatus shiftStatus, IrregularShift irregularShift,
ICollection<CustomizeRotatingShift> customizeRotatingShifts, ICollection<CustomizeCheckoutRegularShift> employeeSettingsShifts)
ICollection<CustomizeRotatingShift> customizeRotatingShifts, ICollection<CustomizeCheckoutRegularShift> employeeSettingsShifts,
ICollection<CheckoutDynamicDeductionItem> checkoutDynamicDeductions)
{
YearInt = Convert.ToInt32(contractStart.ToFarsi().Substring(0, 4));
MonthInt = Convert.ToInt32(contractStart.ToFarsi().Substring(5, 2));
@@ -83,6 +85,7 @@ public class CustomizeCheckout : EntityBase
IrregularShift = irregularShift;
CustomizeRotatingShifts = customizeRotatingShifts;
RegularShifts = employeeSettingsShifts;
CheckoutDynamicDeductions = checkoutDynamicDeductions;
}
@@ -286,6 +289,7 @@ public class CustomizeCheckout : EntityBase
public ICollection<CustomizeCheckoutLoanInstallments> CustomizeCheckoutLoanInstallments { get; set; }
public ICollection<CustomizeCheckoutSalaryAid> CustomizeCheckoutSalaryAids { get; set; }
public ICollection<CustomizeCheckoutReward> CustomizeCheckoutRewards { get; set; }
public ICollection<CheckoutDynamicDeductionItem> CheckoutDynamicDeductions { get; private set; }
public IrregularShift IrregularShift { get; set; }
public ICollection<CustomizeRotatingShift> CustomizeRotatingShifts { get; set; }

View File

@@ -9,6 +9,7 @@ using Company.Domain.CustomizeCheckoutTempAgg.ValueObjects;
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.ValueObjects;
using System.Linq;
using _0_Framework.Application.Enums;
namespace Company.Domain.CustomizeCheckoutTempAgg;
@@ -21,7 +22,8 @@ public class CustomizeCheckoutTemp : EntityBase
{
LateToWorkValue = lateToWorkValue;
}
public CustomizeCheckoutTemp(DateTime contractStart, DateTime contractEnd, long employeeId, string employeeFName,
public CustomizeCheckoutTemp(
DateTime contractStart, DateTime contractEnd, long employeeId, string employeeFName,
string employeeLName, DateTime employeeDateOfBirth,
string employeeNationalCode, string workshopFullName, long workshopId, long? contractId,
double monthlySalary, double fridayPay, double overTimePay, double baseYearsPay, double bonusesPay,
@@ -37,7 +39,8 @@ public class CustomizeCheckoutTemp : EntityBase
ICollection<CustomizeCheckoutTempSalaryAid> customizeCheckoutSalaryAids,
ICollection<CustomizeCheckoutTempReward> customizeCheckoutRewards,
TimeSpan lateToWorkValue, double settingSalary, double dailyWage, WorkshopShiftStatus shiftStatus, IrregularShift irregularShift,
ICollection<CustomizeRotatingShift> customizeRotatingShifts, ICollection<CustomizeCheckoutRegularShift> employeeSettingsShifts)
ICollection<CustomizeRotatingShift> customizeRotatingShifts, ICollection<CustomizeCheckoutRegularShift> employeeSettingsShifts,
ICollection<CheckoutDynamicDeductionItem> checkoutDynamicDeductions)
{
YearInt = Convert.ToInt32(contractStart.ToFarsi().Substring(0, 4));
MonthInt = Convert.ToInt32(contractStart.ToFarsi().Substring(5, 2));
@@ -87,6 +90,7 @@ public class CustomizeCheckoutTemp : EntityBase
IrregularShift = irregularShift;
CustomizeRotatingShifts = customizeRotatingShifts;
RegularShifts = employeeSettingsShifts;
CheckoutDynamicDeductions = checkoutDynamicDeductions;
}
#region Getters
@@ -123,6 +127,7 @@ public class CustomizeCheckoutTemp : EntityBase
public IrregularShift IrregularShift { get; set; }
public ICollection<CustomizeRotatingShift> CustomizeRotatingShifts { get; set; }
public ICollection<CustomizeCheckoutRegularShift> RegularShifts { get; set; }
public ICollection<CheckoutDynamicDeductionItem> CheckoutDynamicDeductions { get; private set; }
#endregion
@@ -389,4 +394,4 @@ public class CustomizeCheckoutTemp : EntityBase
{
HasAmountConflict = hasConflict;
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using _0_Framework.Domain;
using Company.Domain.PaymentTransactionAgg;
using CompanyManagment.App.Contracts.FinancialInvoice;
namespace Company.Domain.FinancialInvoiceAgg;
public class FinancialInvoice : EntityBase
{
public string InvoiceNumber { get; private set; }
public string Description { get; set; }
public FinancialInvoiceStatus Status { get; private set; }
public DateTime? PaidAt { get; private set; }
public double Amount { get; private set; }
public Guid PublicId { get; private set; }
public bool IsActive { get; set; }
public List<PaymentTransaction> PaymentTransactions { get; private set; }
public long ContractingPartyId { get; private set; }
public List<FinancialInvoiceItem> Items { get; private set; }
public FinancialInvoice(double amount, long contractingPartyId, string description)
{
InvoiceNumber = GenerateInvoiceNumber();
Status = FinancialInvoiceStatus.Unpaid;
Amount = amount;
PublicId = Guid.NewGuid();
ContractingPartyId = contractingPartyId;
Description = description;
IsActive = true;
Items = [];
PaymentTransactions = [];
}
public void AddItem(FinancialInvoiceItem item)
{
Items ??= [];
Items.Add(item);
}
public void SetItems(List<FinancialInvoiceItem> items)
{
Items = items;
}
public void SetPaid(DateTime paidAt)
{
Status = FinancialInvoiceStatus.Paid;
PaidAt = paidAt;
}
public void SetUnpaid()
{
Status = FinancialInvoiceStatus.Unpaid;
PaidAt = null;
}
public void SetCancelled()
{
Status = FinancialInvoiceStatus.Cancelled;
PaidAt = null;
}
public void SetRefunded()
{
Status = FinancialInvoiceStatus.Refunded;
PaidAt = null;
}
public void DeActivate()
{
IsActive = false;
}
public void SetInvoiceNumber(string invoiceNumber)
{
InvoiceNumber = invoiceNumber;
}
private string GenerateInvoiceNumber()
{
var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
var random = new Random().Next(1000, 9999);
return $"GZ_{timestamp}{random}";
}
}
public class FinancialInvoiceItem : EntityBase
{
public string Description { get; private set; }
public double Amount { get; private set; }
public FinancialInvoiceItemType Type { get; set; }
public long EntityId { get; set; }
public FinancialInvoice FinancialInvoice { get; set; }
public long FinancialInvoiceId { get; set; }
public FinancialInvoiceItem(string description, double amount,
long financialInvoiceId, FinancialInvoiceItemType type, long entityId)
{
Description = description;
Amount = amount;
FinancialInvoiceId = financialInvoiceId;
Type = type;
EntityId = entityId;
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.FinancialInvoice;
namespace Company.Domain.FinancialInvoiceAgg;
public interface IFinancialInvoiceRepository : IRepository<long, FinancialInvoice>
{
EditFinancialInvoice GetDetails(long id);
List<FinancialInvoiceViewModel> Search(FinancialInvoiceSearchModel searchModel);
Task<FinancialInvoice> GetUnPaidByEntityId(long entityId, FinancialInvoiceItemType financialInvoiceItemType);
}

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using _0_Framework.Domain;
using Company.Domain.FinancialInvoiceAgg;
using Company.Domain.FinancialTransactionAgg;
namespace Company.Domain.FinancialStatmentAgg;

View File

@@ -22,6 +22,8 @@ public interface IFinancialStatmentRepository : IRepository<long, FinancialStatm
Task<OperationResult<ClientFinancialStatementViewModel>> GetDetailsByPublicId(string publicId);
Task<GetFinancialStatementBalanceAmount> GetBalanceAmount(long id);
Task<double> GetClientDebtAmount(long accountId);
Task<FinancialStatmentDetailsByContractingPartyViewModel> GetDetailsByContractingParty(long contractingPartyId,FinancialStatementSearchModel searchModel);
Task<double> GetClientDebtAmountByContractingPartyId(long contractingPartyId);
Task<FinancialStatmentDetailsByContractingPartyViewModel> GetDetailsByContractingParty(long contractingPartyId,FinancialStatementSearchModel searchModel);
Task<FinancialStatment> GetByContractingPartyId(long contractingPartyId);
}

View File

@@ -26,6 +26,35 @@ public class FinancialTransaction : EntityBase
}
/// <summary>
/// ایجاد از طرف بک گراند سرویس
/// </summary>
/// <param name="financialStatementId"></param>
/// <param name="tdateGr"></param>
/// <param name="tdateFa"></param>
/// <param name="description"></param>
/// <param name="typeOfTransaction"></param>
/// <param name="descriptionOption"></param>
/// <param name="deptor"></param>
/// <param name="creditor"></param>
/// <param name="balance"></param>
/// <param name="sentSms"></param>
public FinancialTransaction(long financialStatementId, DateTime tdateGr, string tdateFa, string description,
string typeOfTransaction, string descriptionOption, double deptor, double creditor, double balance,
bool sentSms)
{
FinancialStatementId = financialStatementId;
TdateGr = tdateGr;
TdateFa = tdateFa;
Description = description;
TypeOfTransaction = typeOfTransaction;
DescriptionOption = descriptionOption;
Deptor = deptor;
Creditor = creditor;
Balance = balance;
SentSms = sentSms;
}
public long FinancialStatementId { get; private set; }
public DateTime TdateGr { get; private set; }
public string TdateFa { get; private set; }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.Workshop;
@@ -44,7 +45,7 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
/// <param name="endOfMonthGr"></param>
/// <param name="endOfMonth"></param>
/// <param name="description"></param>
void RollcallServiceCreateTransaction();
Task RollCallServiceCreateTransaction();
Task<PagedResult<GetInstitutionContractListItemsViewModel>> GetList(InstitutionContractListSearchModel searchModel);
Task<GetInstitutionContractListStatsViewModel> GetListStats(InstitutionContractListSearchModel searchModel);
@@ -55,6 +56,9 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
void UpdateStatusIfNeeded(long institutionContractId);
Task<GetInstitutionVerificationDetailsViewModel> GetVerificationDetails(Guid id);
Task<InstitutionContract> GetByPublicIdAsync(Guid id);
InstitutionContractDiscountResponse CalculateDiscount(InstitutionContractSetDiscountRequest request);
InstitutionContractDiscountResponse ResetDiscountCreate(InstitutionContractResetDiscountForCreateRequest request);
#region Extension
@@ -62,9 +66,13 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<InstitutionContractExtensionWorkshopsResponse> GetExtensionWorkshops(InstitutionContractExtensionWorkshopsRequest request);
Task<InstitutionContractExtensionPlanResponse> GetExtensionInstitutionPlan(InstitutionContractExtensionPlanRequest request);
Task<InstitutionContractExtensionPaymentResponse> GetExtensionPaymentMethod(InstitutionContractExtensionPaymentRequest request);
Task<InstitutionContractDiscountResponse> SetDiscountForExtension(
InstitutionContractSetDiscountForExtensionRequest request);
Task<InstitutionContractDiscountResponse> ResetDiscountForExtension(InstitutionContractResetDiscountForExtensionRequest request);
Task<OperationResult> ExtensionComplete(InstitutionContractExtensionCompleteRequest request);
#endregion
#endregion
#region Upgrade(Amendment)
@@ -77,4 +85,73 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<List<InstitutionContractSelectListViewModel>> GetInstitutionContractSelectList(string search, string selected);
Task<List<InstitutionContractPrintViewModel>> PrintAllAsync(List<long> ids);
#region ReminderSMS
/// <summary>
/// دریافت لیست - ارسال پیامک
/// فراخوانی از سمت بک گراند سرویس
/// </summary>
/// <returns></returns>
Task<bool> SendReminderSmsForBackgroundTask();
/// <summary>
/// ارسال پیامک صورت حساب ماهانه
/// </summary>
/// <param name="now"></param>
/// <returns></returns>
Task SendMonthlySms(DateTime now);
/// <summary>
/// ارسال پیامک مسدودی از طرف بک گراند سرویس
/// </summary>
/// <returns></returns>
Task SendBlockSmsForBackgroundTask();
/// <summary>
/// دریافت لیست واجد شرایط بلاک
/// جهت ارسال پیامک مسدودی
/// </summary>
/// <param name="checkDate"></param>
/// <returns></returns>
Task<List<BlockSmsListData>> GetBlockListData(DateTime checkDate);
/// <summary>
/// ارسال پیامک مسدودی
/// </summary>
/// <param name="smsListData"></param>
/// <param name="typeOfSms"></param>
/// <param name="sendMessStart"></param>
/// <param name="sendMessEnd"></param>
/// <returns></returns>
Task SendBlockSmsToContractingParties(List<BlockSmsListData> smsListData, string typeOfSms,
string sendMessStart, string sendMessEnd);
/// <summary>
///دریافت لیست بدهکارن
/// جهت ارسال پیامک
/// </summary>
/// <returns></returns>
Task<List<SmsListData>> GetSmsListData(DateTime checkDate, TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ارسال پیامک های یاد آور بدهی
/// </summary>
/// <returns></returns>
Task SendReminderSmsToContractingParties(List<SmsListData> smsListData, string typeOfSms, string sendMessStart, string sendMessEnd);
#endregion
#region CreateMontlyTransaction
/// <summary>
/// ایجاد سند مالی برای قرارداد ها
/// </summary>
/// <returns></returns>
Task CreateTransactionForInstitutionContracts(DateTime endOfMonthGr, string endOfMonthFa, string description);
#endregion
Task<long> GetIdByInstallmentId(long installmentId);
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Cryptography;
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using Company.Domain.InstitutionContractContactInfoAgg;
using CompanyManagment.App.Contracts.InstitutionContract;
@@ -18,7 +19,8 @@ public class InstitutionContract : EntityBase
string contractEndFa, double contractAmount, double dailyCompenseation, double obligation,
double totalAmount, int extensionNo, string workshopManualCount, string employeeManualCount, string description,
string officialCompany, string typeOfcontract, string hasValueAddedTax, double valueAddedTax,
List<InstitutionContractWorkshopInitial> workshopDetails, long lawId)
List<InstitutionContractWorkshopInitial> workshopDetails, long lawId,
int discountPercentage, double discountAmount)
{
ContractNo = contractNo;
RepresentativeId = representativeId;
@@ -56,8 +58,12 @@ public class InstitutionContract : EntityBase
WorkshopGroup = new InstitutionContractWorkshopGroup(id, workshopDetails);
PublicId = Guid.NewGuid();
LawId = lawId;
DiscountPercentage = discountPercentage;
DiscountAmount = discountAmount;
}
public long LawId { get; private set; }
public string ContractNo { get; private set; }
@@ -127,6 +133,10 @@ public class InstitutionContract : EntityBase
public DateTime VerifyCodeCreation { get; private set; }
public string VerifierFullName { get; private set; }
public string VerifierPhoneNumber { get; private set; }
public double DiscountAmount { get; private set; }
public int DiscountPercentage { get; private set; }
[NotMapped] public bool VerifyCodeExpired => VerifyCodeCreation.Add(ExpireTime) <= DateTime.Now;
@@ -371,20 +381,3 @@ public enum InstitutionContractAmendmentChangeType
WorkshopCreated
}
public enum InstitutionContractVerificationStatus
{
/// <summary>
/// در انتظار تایید
/// </summary>
PendingForVerify = 0,
/// <summary>
/// در انتظار کارپوشه
/// </summary>
PendingWorkflow = 1,
/// <summary>
/// تایید شده
/// </summary>
Verified = 2
}

View File

@@ -65,6 +65,7 @@ public class InstitutionContractExtensionTemp
MonthlyPayment = monthly;
OneTimePayment = oneTime;
}
}

View File

@@ -1,5 +1,6 @@
using System;
using _0_Framework.Domain;
using Company.Domain.FinancialInvoiceAgg;
using CompanyManagment.App.Contracts.PaymentTransaction;
namespace Company.Domain.PaymentTransactionAgg;
@@ -9,14 +10,15 @@ namespace Company.Domain.PaymentTransactionAgg;
/// </summary>
public class PaymentTransaction:EntityBase
{
/// <summary>
/// سازنده کلاس PaymentTransaction با دریافت اطلاعات تراکنش.
/// </summary>
/// <param name="contractingPartyId">شناسه طرف قرارداد</param>
/// <param name="amount">مبلغ تراکنش</param>
/// <param name="contractingPartyName"></param>
/// <param name="callBackUrl"></param>
public PaymentTransaction(long contractingPartyId,
/// <summary>
/// سازنده کلاس PaymentTransaction با دریافت اطلاعات تراکنش.
/// </summary>
/// <param name="contractingPartyId">شناسه طرف قرارداد</param>
/// <param name="amount">مبلغ تراکنش</param>
/// <param name="contractingPartyName"></param>
/// <param name="callBackUrl"></param>
/// <param name="gateway"></param>
public PaymentTransaction(long contractingPartyId,
double amount,
string contractingPartyName,string callBackUrl,
PaymentTransactionGateWay gateway)
@@ -74,6 +76,9 @@ public class PaymentTransaction:EntityBase
public string Rrn { get; private set; }
public string DigitalReceipt { get; private set; }
public FinancialInvoice FinancialInvoice { get; set; }
public long? FinancialInvoiceId { get; set; }
public void SetPaid(string cardNumber,string bankName,string rrn,string digitalReceipt)
{

View File

@@ -0,0 +1,30 @@
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using CompanyManagment.App.Contracts.SmsResult;
using System.Threading.Tasks;
namespace Company.Domain.SmsResultAgg;
public interface ISmsSettingsRepository : IRepository<long, SmsSetting>
{
/// <summary>
/// ویرایش پیامک خودکار
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<EditSmsSetting> GetSmsSettingToEdit(long id);
/// <summary>
/// دریافت لیست پیامک های خودکار بر اساس نوع آن
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<SmsSettingViewModel> GetSmsSettingsByType(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// حذف از دیتابیس
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task RemoveItem(long id);
}

View File

@@ -0,0 +1,72 @@
using _0_Framework.Application.Enums;
using _0_Framework.Domain;
using System;
namespace Company.Domain.SmsResultAgg;
public class SmsSetting : EntityBaseWithoutCreationDate
{
/// <summary>
/// ایجاد تنظیمات پیامک
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <param name="dayOfMonth"></param>
/// <param name="timeOfDay"></param>
public SmsSetting(TypeOfSmsSetting typeOfSmsSetting, int dayOfMonth, TimeSpan timeOfDay)
{
TypeOfSmsSetting = typeOfSmsSetting;
DayOfMonth = dayOfMonth;
TimeOfDay = timeOfDay;
IsActive = true;
}
/// <summary>
/// نوع پیامک
/// </summary>
public TypeOfSmsSetting TypeOfSmsSetting { get; set; }
/// <summary>
/// عدد روز از ماه
/// </summary>
public int DayOfMonth { get; set; }
/// <summary>
/// ساعت
/// </summary>
public TimeSpan TimeOfDay { get; set; }
/// <summary>
/// فعال/غیرفعال
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// ویرایش تنظیمات پیامک
/// </summary>
/// <param name="dayOfMonth"></param>
/// <param name="timeOfDay"></param>
public void Edit(int dayOfMonth, TimeSpan timeOfDay)
{
DayOfMonth = dayOfMonth;
TimeOfDay = timeOfDay;
}
/// <summary>
/// فعال نمودن
/// </summary>
public void Active()
{
IsActive = true;
}
/// <summary>
/// غیر فعال نمودن
/// </summary>
public void DeActive()
{
IsActive = false;
}
}

View File

@@ -0,0 +1,47 @@
using System.Drawing;
using CompanyManagment.App.Contracts.Workshop;
using OfficeOpenXml;
using OfficeOpenXml.Style;
namespace CompanyManagement.Infrastructure.Excel.WorkshopsRollCall;
public class WorkshopRollCallExcelExporter
{
public static byte[] Export(List<WorkshopRollCallExcelViewModel> workshops)
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("Workshops");
// Header
ws.Cells[1, 1].Value = "نام کارگاه";
ws.Cells[1, 2].Value = "فعال/غیرفعال";
ws.Cells[1, 3].Value = "تعداد پرسنل";
ws.Cells[1, 4].Value = "نام کارفرما";
ws.Row(1).Style.Font.Bold = true;
ws.Row(1).Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Row(1).Style.Fill.BackgroundColor.SetColor(Color.LightGray);
int row = 2;
foreach (var w in workshops)
{
ws.Cells[row, 1].Value = w.WorkshopName;
ws.Cells[row, 2].Value = w.IsActive ? "فعال" : "غیرفعال";
ws.Cells[row, 3].Value = w.PersonnelCount;
ws.Cells[row, 4].Value = w.EmployerName;
if (!w.IsActive)
{
using (var range = ws.Cells[row, 1, row, 4])
{
range.Style.Fill.PatternType = ExcelFillStyle.Solid;
range.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
}
}
row++;
}
ws.Cells[ws.Dimension.Address].AutoFitColumns();
return package.GetAsByteArray();
}
}
}

View File

@@ -0,0 +1,11 @@
namespace CompanyManagement.Infrastructure.Excel.WorkshopsRollCall
{
public class WorkshopRollCallExcelViewModel
{
public string WorkshopName { get; set; }
public bool IsActive { get; set; }
public int PersonnelCount { get; set; }
public string EmployerName { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace CompanyManagment.App.Contracts.AndroidApkVersion;
public enum ApkType
{
WebView,
FaceDetection
}

View File

@@ -4,12 +4,15 @@ using Microsoft.AspNetCore.Http;
namespace CompanyManagment.App.Contracts.AndroidApkVersion;
public record AndroidApkVersionInfo(int LatestVersionCode, string LatestVersionName, bool ShouldUpdate, bool IsForceUpdate, string DownloadUrl, string ReleaseNotes);
public interface IAndroidApkVersionApplication
{
Task<OperationResult> CreateAndActive(IFormFile file);
Task<OperationResult> CreateAndDeActive(IFormFile file);
Task<string> GetLatestActiveVersionPath();
Task<OperationResult> CreateAndActive(IFormFile file, ApkType apkType, string versionName, string versionCode, bool isForce = false);
Task<OperationResult> CreateAndDeActive(IFormFile file, ApkType apkType, string versionName, string versionCode, bool isForce = false);
Task<string> GetLatestActiveVersionPath(ApkType apkType);
Task<AndroidApkVersionInfo> GetLatestActiveInfo(ApkType apkType, int currentVersionCode);
OperationResult Remove(long id);
bool HasAndroidApkToDownload();
bool HasAndroidApkToDownload(ApkType apkType);
}

View File

@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.Base;
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.ValueObjects;
@@ -18,8 +20,6 @@ namespace CompanyManagment.App.Contracts.CustomizeCheckout;
public class CustomizeCheckoutMandatoryViewModel
{
/// <summary>
/// حقوق ماهانه
/// </summary>
@@ -159,7 +159,7 @@ public class CustomizeCheckoutMandatoryViewModel
/// </summary>
public double TotalDeductionsDouble => FineAbsenceDeduction + InsuranceDeduction + LateToWorkDeduction +
EarlyExitDeduction + SalaryAidDeduction + InstallmentDeduction +
FineDeduction + TaxDeduction;
FineDeduction + TaxDeduction+ DynamicDeductions.Sum(x=>x.Amount.MoneyToDouble());
/// <summary>
/// مجموع مطالبات
@@ -207,6 +207,8 @@ public class CustomizeCheckoutMandatoryViewModel
public ICollection<CustomizeRotatingShift> CustomizeRotatingShifts { get; set; } = [];
public ICollection<CustomizeSifts> EmployeeSettingsShifts { get; set; } = [];
public List<CheckoutDynamicDeductionItem> DynamicDeductions { get; set; } = new();
}

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Runtime;
using System.Security.AccessControl;
using _0_Framework.Application.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.Base;
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
using _0_Framework.Domain.CustomizeCheckoutShared.ValueObjects;
@@ -12,113 +13,115 @@ using CompanyManagment.App.Contracts.Loan;
using CompanyManagment.App.Contracts.Reward;
using CompanyManagment.App.Contracts.SalaryAid;
namespace CompanyManagment.App.Contracts.CustomizeCheckout
namespace CompanyManagment.App.Contracts.CustomizeCheckout;
public class CustomizeCheckoutViewModel
{
public class CustomizeCheckoutViewModel
{
public long Id { get; set; }
public DateTime CreationDate { get; set; }
public string Month { get; set; }
public string Year { get; set; }
public int PrintCounter { get; set; }
public long Id { get; set; }
public DateTime CreationDate { get; set; }
public string Month { get; set; }
public string Year { get; set; }
public int PrintCounter { get; set; }
public long EmployeeId { get; set; }
public string EmployeeFName { get; set; }
public string EmployeeLName { get; set; }
public string EmployeeFullName => $"{EmployeeFName} {EmployeeLName}";
public string FatherName { get; set; }
public string NationalCode { get; set; }
public string DateOfBirth { get; set; }
public long PersonnelCode { get; set; }
public string PersonnelCodeString => PersonnelCode.ToString();
public long EmployeeId { get; set; }
public string EmployeeFName { get; set; }
public string EmployeeLName { get; set; }
public string EmployeeFullName => $"{EmployeeFName} {EmployeeLName}";
public string FatherName { get; set; }
public string NationalCode { get; set; }
public string DateOfBirth { get; set; }
public long PersonnelCode { get; set; }
public string PersonnelCodeString => PersonnelCode.ToString();
public string WorkshopName { get; set; }
public long WorkshopId { get; set; }
public string WorkshopName { get; set; }
public long WorkshopId { get; set; }
public long EmployerId { get; set; }
public string EmployerName { get; set; }
public List<EmployerViewModel> EmployerList { get; set; }
public long EmployerId { get; set; }
public string EmployerName { get; set; }
public List<EmployerViewModel> EmployerList { get; set; }
public long ContractId { get; set; }
public string ContractNo { get; set; }
public DateTime ContractStartGr { get; set; }
public DateTime ContractEndGr { get; set; }
public string ContractStartFa { get; set; }
public string ContractEndFa { get; set; }
//[JsonIgnore]
//public string LastDayOfWork => LeftWorkDateGr.AddDays(-1).ToFarsi();
//[JsonIgnore]
//public string LeftWorkDateFa => LeftWorkDateGr.ToFarsi();
public DateTime LeftWorkDateGr { get; set; }
public long ContractId { get; set; }
public string ContractNo { get; set; }
public DateTime ContractStartGr { get; set; }
public DateTime ContractEndGr { get; set; }
public string ContractStartFa { get; set; }
public string ContractEndFa { get; set; }
//[JsonIgnore]
//public string LastDayOfWork => LeftWorkDateGr.AddDays(-1).ToFarsi();
//[JsonIgnore]
//public string LeftWorkDateFa => LeftWorkDateGr.ToFarsi();
public DateTime LeftWorkDateGr { get; set; }
public string SumOfWorkingDays { get; set; }
public string SumOfWorkingDays { get; set; }
public string MonthlySalary { get; set; }
public string BaseYearsPay { get; set; }
public string MonthlySalary { get; set; }
public string BaseYearsPay { get; set; }
public string MarriedAllowance { get; set; }
public string OvertimePay { get; set; }
public string NightworkPay { get; set; }
public string FridayPay { get; set; }
public string MissionPay { get; set; }
public string ShiftPay { get; set; }
public string FamilyAllowance { get; set; }
public string BonusesPay { get; set; }
public string LeavePay { get; set; }
public string RewardPay { get; set; }
public string MarriedAllowance { get; set; }
public string OvertimePay { get; set; }
public string NightworkPay { get; set; }
public string FridayPay { get; set; }
public string MissionPay { get; set; }
public string ShiftPay { get; set; }
public string FamilyAllowance { get; set; }
public string BonusesPay { get; set; }
public string LeavePay { get; set; }
public string RewardPay { get; set; }
public bool IsBirthday { get; set; } = true;
public string FineDeduction { get; set; }
public string InsuranceDeduction { get; set; }
public string TaxDeducation { get; set; }
public string InstallmentDeduction { get; set; }
public string SalaryAidDeduction { get; set; }
public string AbsenceDeduction { get; set; }
public string EarlyExitDeduction { get; set; }
public string LateToWorkDeduction { get; set; }
public bool IsBirthday { get; set; } = true;
public string FineDeduction { get; set; }
public string InsuranceDeduction { get; set; }
public string TaxDeducation { get; set; }
public string InstallmentDeduction { get; set; }
public string SalaryAidDeduction { get; set; }
public string AbsenceDeduction { get; set; }
public string EarlyExitDeduction { get; set; }
public string LateToWorkDeduction { get; set; }
public string TotalClaims { get; set; }
public string TotalDeductions { get; set; }
public string TotalPayment { get; set; }
public string TotalClaims { get; set; }
public string TotalDeductions { get; set; }
public string TotalPayment { get; set; }
public List<FineViewModel> FineViewModelList { get; set; }
public List<RewardViewModel> RewardViewModels { get; set; }
public List<LoanInstallmentViewModel> InstallmentViewModels { get; set; }
public List<SalaryAidViewModel> SalaryAidViewModels { get; set; }
public bool TotalPaymentHide { get; set; }
public PersonnelCheckoutDailyRollCallViewModel MonthlyRollCall { get; set; }
public double TotalPaymentD { get; set; }
public List<FineViewModel> FineViewModelList { get; set; }
public List<RewardViewModel> RewardViewModels { get; set; }
public List<LoanInstallmentViewModel> InstallmentViewModels { get; set; }
public List<SalaryAidViewModel> SalaryAidViewModels { get; set; }
public bool TotalPaymentHide { get; set; }
public PersonnelCheckoutDailyRollCallViewModel MonthlyRollCall { get; set; }
public double TotalPaymentD { get; set; }
public string TotalLateToWorkDeduction { get; set; }
public string TotalLateToWorkDeduction { get; set; }
public string LateToWorkValue { get; set; }
public string LateToWorkValue { get; set; }
public string SettingSalary { get; set; }
public string DailyWage { get; set; }
public WorkshopShiftStatus ShiftStatus { get; set; }
public string SettingSalary { get; set; }
public string DailyWage { get; set; }
public WorkshopShiftStatus ShiftStatus { get; set; }
public string EmployeePicture { get; set; }
public string EmployeePicture { get; set; }
public IrregularShift IrregularShift { get; set; }
public List<CustomizeRotatingShift> CustomizeRotatingShifts { get; set; }
public List<CustomizeSifts> RegularShift { get; set; }
public IrregularShift IrregularShift { get; set; }
public List<CustomizeRotatingShift> CustomizeRotatingShifts { get; set; }
public List<CustomizeSifts> RegularShift { get; set; }
public bool HasAmountConflict { get; set; }
public bool HasAmountConflict { get; set; }
//public bool HasLeft { get; set; }
//public string IsBlockCantracingParty { get; set; }
//public string IsActiveString { get; set; }
//public long WorkingHoursId { get; set; }
//public string ArchiveCode { get; set; }
//public string ConsumableItems { get; set; }
//public string HousingAllowance { get; set; }
//public string YearsPay { get; set; }
// New: up to three dynamic deduction items (name, count, amount)
public List<CheckoutDynamicDeductionItem> CheckoutDynamicDeductions { get; set; } = new List<CheckoutDynamicDeductionItem>();
//public bool HasLeft { get; set; }
//public string IsBlockCantracingParty { get; set; }
//public string IsActiveString { get; set; }
//public long WorkingHoursId { get; set; }
//public string ArchiveCode { get; set; }
//public string ConsumableItems { get; set; }
//public string HousingAllowance { get; set; }
//public string YearsPay { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public class CreateFinancialInvoice
{
public double Amount { get; set; }
public long ContractingPartyId { get; set; }
public string Description { get; set; }
public List<CreateFinancialInvoiceItem>? Items { get; set; }
}
public class CreateFinancialInvoiceItem
{
public string Description { get; set; }
public double Amount { get; set; }
public FinancialInvoiceItemType Type { get; set; }
public long EntityId { get; set; }
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public class EditFinancialInvoice
{
public long Id { get; set; }
public string InvoiceNumber { get; set; }
public string Description { get; set; }
public double Amount { get; set; }
public FinancialInvoiceStatus Status { get; set; }
public List<EditFinancialInvoiceItem>? Items { get; set; }
}
public class EditFinancialInvoiceItem
{
public long Id { get; set; }
public string Description { get; set; }
public double Amount { get; set; }
public FinancialInvoiceItemType Type { get; set; }
public long EntityId { get; set; }
}

View File

@@ -0,0 +1,25 @@
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public enum FinancialInvoiceItemType
{
/// <summary>
/// قسط قرارداد خرید از موسسه
/// </summary>
BuyInstitutionContractInstallment,
/// <summary>
/// خرید قرارداد از موسسه
/// </summary>
BuyInstitutionContract,
/// <summary>
///قسط ارتقا قرارداد موسسه
/// </summary>
AmendmentInstitutionContractInstallment,
/// <summary>
/// ارتقا قرارداد موسسه
/// </summary>
AmendmentInstitutionContract,
/// <summary>
/// بدهی قبلی
/// </summary>
PreviousDebt,
}

View File

@@ -0,0 +1,12 @@
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public class FinancialInvoiceSearchModel
{
public string? Description { get; set; }
public FinancialInvoiceStatus? Status { get; set; }
public long? ContractingPartyId { get; set; }
public string? FromDate { get; set; }
public string? ToDate { get; set; }
public double? MinAmount { get; set; }
public double? MaxAmount { get; set; }
}

View File

@@ -0,0 +1,21 @@
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public enum FinancialInvoiceStatus
{
/// <summary>
/// پرداخت نشده
/// </summary>
Unpaid = 0,
/// <summary>
/// پرداخت شده کامل
/// </summary>
Paid = 1,
/// <summary>
/// فاکتور لغو شده
/// </summary>
Cancelled = 4,
/// <summary>
/// // بازپرداخت شده (در صورت برگشت وجه)
/// </summary>
Refunded = 5,
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public class FinancialInvoiceViewModel
{
public long Id { get; set; }
public string InvoiceNumber { get; set; }
public string Description { get; set; }
public string Status { get; set; }
public string PaidAt { get; set; }
public double Amount { get; set; }
public Guid PublicId { get; set; }
public long ContractingPartyId { get; set; }
public string ContractingPartyName { get; set; }
public string CreationDate { get; set; }
public int ItemsCount { get; set; }
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.FinancialInvoice;
public interface IFinancialInvoiceApplication
{
OperationResult Create(CreateFinancialInvoice command);
OperationResult Edit(EditFinancialInvoice command);
OperationResult SetPaid(long id, DateTime paidAt);
OperationResult SetUnpaid(long id);
OperationResult SetCancelled(long id);
OperationResult SetRefunded(long id);
EditFinancialInvoice GetDetails(long id);
List<FinancialInvoiceViewModel> Search(FinancialInvoiceSearchModel searchModel);
}

View File

@@ -9,6 +9,7 @@ public class FinancialStatmentViewModel
public long Id { get; set; }
public long ContractingPartyId { get; set; }
public string ContractingPartyName { get; set; }
public string PublicId { get; set; }
public List<FinancialTransactionViewModel> FinancialTransactionViewModels { get; set; }

View File

@@ -10,6 +10,7 @@ public class FinancialTransactionViewModel
public string TdateFa { get; set; }
public string Description { get; set; }
public string TypeOfTransaction { get; set; }
public string DescriptionOption { get; set; }
public double Deptor { get; set; }
public string DeptorString { get; set; }
public double Creditor { get; set; }
@@ -20,4 +21,7 @@ public class FinancialTransactionViewModel
public string MessageText { get; set; }
public string SentSmsDateFa { get; set; }
public int Counter { get; set; }
}

View File

@@ -0,0 +1,20 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace CompanyManagment.App.Contracts.Hubs;
public class SendSmsHub : Hub
{
public async Task send(long id)
{
await Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName(id));
}
public static string GetGroupName(long id)
{
return $"group-sms-{id}";
}
}

View File

@@ -87,7 +87,7 @@ public class CreateInstitutionContractRequest
/// <summary>
/// مبلغ کل قرارداد
/// </summary>
public double TotalAmount { get; set; }
public double PaymentAmount { get; set; }
/// <summary>
/// آیا قرارداد اقساطی است؟
@@ -102,6 +102,10 @@ public class CreateInstitutionContractRequest
public double OneMonthAmount { get; set; }
public long LawId { get; set; }
public int DiscountPercentage { get; set; }
public double DiscountAmount { get; set; }
}
/// <summary>
/// مدت زمان قرارداد نهاد

View File

@@ -213,9 +213,11 @@ public interface IInstitutionContractApplication
Task<GetInstitutionVerificationDetailsViewModel> GetVerificationDetails(Guid id);
Task<OperationResult<OtpResultViewModel>> SendVerifyOtp(Guid id);
Task<OperationResult> VerifyOtp(Guid publicId, string code);
Task<OperationResult<string>> VerifyOtpAndMakeGateway(Guid publicId, string code, string callbackUrl);
Task<InstitutionContractWorkshopDetailViewModel> GetWorkshopInitialDetails(long workshopDetailsId);
InstitutionContractDiscountResponse CalculateDiscount(InstitutionContractSetDiscountRequest request);
InstitutionContractDiscountResponse ResetDiscountCreate(InstitutionContractResetDiscountForCreateRequest request);
#region Extension
Task<InstitutionContractExtensionInquiryResult> GetExtensionInquiry(long previousContractId);
@@ -228,6 +230,12 @@ public interface IInstitutionContractApplication
Task<InstitutionContractExtensionPaymentResponse> GetExtensionPaymentMethod(
InstitutionContractExtensionPaymentRequest request);
Task<InstitutionContractDiscountResponse> SetDiscountForExtension(
InstitutionContractSetDiscountForExtensionRequest request);
Task<InstitutionContractDiscountResponse> ResetDiscountForExtension(
InstitutionContractResetDiscountForExtensionRequest request);
Task<OperationResult> ExtensionComplete(InstitutionContractExtensionCompleteRequest request);
Task<List<InstitutionContractSelectListViewModel>> GetInstitutionContractSelectList(string search,string selected);
@@ -251,6 +259,77 @@ public interface IInstitutionContractApplication
/// <param name="id"></param>
/// <returns></returns>
Task<InstitutionContractPrintViewModel> PrintOneAsync(long id);
Task<OperationResult> SetPendingWorkflow(long entityId);
Task<long> GetIdByInstallmentId(long installmentId);
}
public class InstitutionContractDiscountResponse
{
public InstitutionContractDiscountOneTimeViewModel OneTime { get; set; }
public InstitutionContractDiscountMonthlyViewModel Monthly { get; set; }
}
public class InstitutionContractDiscountMonthlyViewModel:InstitutionContractDiscountOneTimeViewModel
{
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractDiscountOneTimeViewModel
{
/// <summary>
/// مجموع مبالغ
/// </summary>
public string TotalAmount { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
public string DiscountedAmount { get; set; }
public int DiscountPercetage { get; set; }
public string Obligation { get; set; }
public string OneMonthAmount { get; set; }
}
public class InstitutionContractResetDiscountForCreateRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
}
public class InstitutionContractSetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractResetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractSetDiscountRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractPrintViewModel

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using _0_Framework.Application.Enums;
using CompanyManagment.App.Contracts.InstitutionContractContactinfo;
namespace CompanyManagment.App.Contracts.InstitutionContract;
@@ -11,4 +12,15 @@ public class InstitutionContractExtensionWorkshopsRequest
public string Province { get; set; }
public string Address { get; set; }
public List<EditContactInfo> ContactInfos { get; set; }
/// <summary>
/// اطلاعات شخص حقیقی
/// </summary>
public CreateInstitutionContractRealPartyRequest RealParty { get; set; }
/// <summary>
/// اطلاعات شخص حقوقی
/// </summary>
public CreateInstitutionContractLegalPartyRequest LegalParty { get; set; }
public LegalType LegalType { get; set; }
}

View File

@@ -27,7 +27,13 @@ public class InstitutionContractInstallmentViewModel
/// مبلغ قسط
/// </summary>
public string Amount { get; set; }
/// <summary>
/// مبلغ قسط
/// Double
/// </summary>
public double AmountDouble { get; set; }
/// <summary>
/// عدد قسط فارسی
/// </summary>

View File

@@ -17,6 +17,9 @@ public class InstitutionContractPaymentOneTimeViewModel
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
public string DiscountedAmount { get; set; }
public int DiscountPercetage { get; set; }
}
public class InstitutionContractPaymentMonthlyViewModel:InstitutionContractPaymentOneTimeViewModel
{

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using _0_Framework.Application.Enums;
using CompanyManagment.App.Contracts.Employer;
using CompanyManagment.App.Contracts.Workshop;
@@ -25,6 +26,7 @@ public class InstitutionContractViewModel
public DateTime ContractEndGr { get; set; }
public string ContractEndFa { get; set; }
public string ContractAmount { get; set; }
public double ContractAmountDouble { get; set; }
public string DailyCompenseation { get; set; }
public string Obligation { get; set; }
@@ -70,4 +72,9 @@ public class InstitutionContractViewModel
public int LeftWorkEmployeeCount { get; set; }
public int InsuranceLeftWorkEmployeeCount { get; set; }
public string IsExpier { get; set; }
public bool IsInstallment { get; set; }
public InstitutionContractVerificationStatus VerificationStatus { get; set; }
public List<InstitutionContractInstallmentViewModel> InstallmentList { get; set; }
}

View File

@@ -0,0 +1,97 @@
namespace CompanyManagment.App.Contracts.InstitutionContract;
/// <summary>
/// لیست پیامکهای بدهکاران قرارداد ملی
/// </summary>
public class SmsListData
{
/// <summary>
/// شماره تماس طرف حساب
/// </summary>
public string PhoneNumber { get; set; }
/// <summary>
/// تمپلیت آی دی
/// </summary>
public int TemplateId { get; set; }
/// <summary>
/// نام طرف حساب
/// </summary>
public string PartyName { get; set; }
/// <summary>
/// مبلغ بدهی
/// </summary>
public string Amount { get; set; }
/// <summary>
/// آی دی طرف حساب
/// </summary>
public long ContractingPartyId { get; set; }
/// <summary>
/// آی دی صورت حساب مالی
/// </summary>
public string AproveId { get; set; }
/// <summary>
/// نوع متد ارسال پیامک
/// </summary>
public string TypeOfSmsMethod { get; set; }
/// <summary>
/// پابلیک آی دی بخش یک
/// </summary>
public string Code1 { get; set; }
/// <summary>
/// پابلیک آی دی بخش دو
/// </summary>
public string Code2 { get; set; }
/// <summary>
/// ای دی قراداد مالی
/// </summary>
public long InstitutionContractId { get; set; }
}
/// <summary>
/// لیست پیامک های بلاک
/// </summary>
public class BlockSmsListData
{
/// <summary>
/// شماره تماس طرف حساب
/// </summary>
public string PhoneNumber { get; set; }
/// <summary>
/// نام طرف حساب
/// </summary>
public string PartyName { get; set; }
/// <summary>
/// مبلغ بدهی
/// </summary>
public string Amount { get; set; }
/// <summary>
/// آی دی طرف حساب
/// </summary>
public long ContractingPartyId { get; set; }
/// <summary>
/// نوع حساب - رسمی یا غیر رسمی
/// </summary>
public string AccountType { get; set; }
/// <summary>
/// ای دی قراداد مالی
/// </summary>
public long InstitutionContractId { get; set; }
/// <summary>
/// آی دی صورت حساب مالی
/// </summary>
public string AproveId { get; set; }
}

View File

@@ -0,0 +1,62 @@
using _0_Framework.Application.Enums;
using System;
using System.Collections.Generic;
using _0_Framework.Domain;
namespace CompanyManagment.App.Contracts.SmsResult;
/// <summary>
/// مدل ایجاد تنظیمات پیامک
/// </summary>
public class CreateSmsSetting
{
/// <summary>
/// نوع پیامک
/// </summary>
public TypeOfSmsSetting TypeOfSmsSetting { get; set; }
/// <summary>
/// عدد روز از ماه
/// </summary>
public int DayOfMonth { get; set; }
/// <summary>
/// ساعت
/// </summary>
public TimeSpan TimeOfDay { get; set; }
}
/// <summary>
/// ویرایش تنظیمات پیامک
/// </summary>
public class EditSmsSetting : CreateSmsSetting
{
/// <summary>
/// آی دی
/// </summary>
public long Id { get; set; }
/// <summary>
/// فعال/غیرفعال
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// نمایش ساعت و دقیقه
/// </summary>
public string TimeOfDayDisplay { get; set; }
}
/// <summary>
/// ویو مدل تنظیمات پیامک
/// </summary>
public class SmsSettingViewModel
{
/// <summary>
/// لیست تنظیمات پیامک
/// </summary>
public List<EditSmsSetting> EditSmsSettings { get; set; }
}

View File

@@ -0,0 +1,78 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using CompanyManagment.App.Contracts.InstitutionContract;
namespace CompanyManagment.App.Contracts.SmsResult;
public interface ISmsSettingApplication
{
/// <summary>
/// دریافت لیست پیامک های خودکار بر اساس نوع آن
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
public Task<SmsSettingViewModel> GetSmsSettingsByType(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ایجاد تنظیمات پیامک یادآور
/// </summary>
/// <param name="dayOfMonth"></param>
/// <param name="timeOfDay"></param>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<OperationResult> CreateSmsSetting(int dayOfMonth, string timeOfDay, TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ویرایش پیامک خودکار
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<EditSmsSetting> GetSmsSettingToEdit(long id);
/// <summary>
/// ایجاد تنظیمات پیامک یادآور
/// </summary>
/// <param name="dayOfMonth"></param>
/// <param name="timeOfDay"></param>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<OperationResult> EditeSmsSetting(EditSmsSetting command);
/// <summary>
/// حذف از دیتابیس
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task RemoveSetting(long id);
/// <summary>
/// دریافت لیست بدهکاران
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<List<SmsListData>> GetSmsListData(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// دریافت لیست کسانی که باید بلاک شوند
/// </summary>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
Task<List<BlockSmsListData>> GetBlockSmsListData(TypeOfSmsSetting typeOfSmsSetting);
/// <summary>
/// ارسال پیامک یاد آور آنی
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
Task<OperationResult> InstantSendReminderSms(List<SmsListData> command);
/// <summary>
/// ارسال پیامک مسدودس
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
Task<OperationResult> InstantSendBlockSms(List<BlockSmsListData> command);
}

View File

@@ -1,13 +1,11 @@
using System;
using System.IO;
using AccountManagement.Domain.TaskAgg;
using ApkReader;
using Company.Domain.AndroidApkVersionAgg;
using CompanyManagment.App.Contracts.AndroidApkVersion;
using CompanyManagment.Application.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.IO;
using System.Threading.Tasks;
using _0_Framework.Application;
@@ -24,7 +22,7 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
_taskRepository = taskRepository;
}
public async Task<OperationResult> CreateAndActive(IFormFile file)
public async Task<OperationResult> CreateAndActive(IFormFile file, ApkType apkType, string versionName, string versionCode, bool isForce = false)
{
OperationResult op = new OperationResult();
@@ -36,22 +34,26 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
if (Path.GetExtension(file.FileName).ToLower() != ".apk")
return op.Failed("لطفا فایلی با پسوند .apk وارد کنید");
if (string.IsNullOrWhiteSpace(versionName))
return op.Failed("لطفا نام ورژن را وارد کنید");
if (string.IsNullOrWhiteSpace(versionCode))
return op.Failed("لطفا کد ورژن را وارد کنید");
#endregion
var activeApks = _androidApkVersionRepository.GetActives();
var activeApks = _androidApkVersionRepository.GetActives(apkType);
await activeApks.ExecuteUpdateAsync(setter => setter.SetProperty(e => e.IsActive, IsActive.False));
_androidApkVersionRepository.SaveChanges();
var folderName = apkType == ApkType.WebView ? "GozreshgirWebView" : "GozreshgirFaceDetection";
var path = Path.Combine($"{_taskRepository.GetWebEnvironmentPath()}", "Storage",
"Apk", "Android", "GozreshgirWebView");
"Apk", "Android", folderName);
Directory.CreateDirectory(path);
//var apk = new ApkReader.ApkReader().Read(file.OpenReadStream());
string uniqueFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}{Path.GetExtension(file.FileName)}";
string uniqueFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}.v{versionName}{Path.GetExtension(file.FileName)}";
string filepath = Path.Combine(path, uniqueFileName);
@@ -60,13 +62,13 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
await file.CopyToAsync(stream);
}
var entity = new AndroidApkVersion("0", "0", IsActive.True, filepath);
var entity = new AndroidApkVersion(versionName, versionCode, IsActive.True, filepath,apkType,isForce);
_androidApkVersionRepository.Create(entity);
_androidApkVersionRepository.SaveChanges();
return op.Succcedded();
}
public async Task<OperationResult> CreateAndDeActive(IFormFile file)
public async Task<OperationResult> CreateAndDeActive(IFormFile file, ApkType apkType, string versionName, string versionCode, bool isForce = false)
{
OperationResult op = new OperationResult();
@@ -78,18 +80,22 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
if (Path.GetExtension(file.FileName).ToLower() != ".apk")
return op.Failed("لطفا فایلی با پسوند .apk وارد کنید");
if (string.IsNullOrWhiteSpace(versionName))
return op.Failed("لطفا نام ورژن را وارد کنید");
if (string.IsNullOrWhiteSpace(versionCode))
return op.Failed("لطفا کد ورژن را وارد کنید");
#endregion
var folderName = apkType == ApkType.WebView ? "GozreshgirWebView" : "GozreshgirFaceDetection";
var path = Path.Combine($"{_taskRepository.GetWebEnvironmentPath()}", "Storage",
"Apk", "Android", "GozreshgirWebView");
"Apk", "Android", folderName);
Directory.CreateDirectory(path);
var apk = new ApkReader.ApkReader().Read(file.OpenReadStream());
string uniqueFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}.v{apk.VersionName}{Path.GetExtension(file.FileName)}";
string uniqueFileName = $"{Path.GetFileNameWithoutExtension(file.FileName)}.v{versionName}{Path.GetExtension(file.FileName)}";
string filepath = Path.Combine(path, uniqueFileName);
@@ -98,14 +104,15 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
await file.CopyToAsync(stream);
}
var entity = new AndroidApkVersion(apk.VersionName, apk.VersionCode, IsActive.False, filepath);
var entity = new AndroidApkVersion(versionName, versionCode, IsActive.False, filepath,apkType);
_androidApkVersionRepository.Create(entity);
_androidApkVersionRepository.SaveChanges();
return op.Succcedded();
}
public async Task<string> GetLatestActiveVersionPath()
public async Task<string> GetLatestActiveVersionPath(ApkType apkType)
{
return await _androidApkVersionRepository.GetLatestActiveVersionPath();
return await _androidApkVersionRepository.GetLatestActiveVersionPath(apkType);
}
public OperationResult Remove(long id)
@@ -127,8 +134,22 @@ public class AndroidApkVersionApplication : IAndroidApkVersionApplication
return op.Succcedded();
}
public bool HasAndroidApkToDownload()
public bool HasAndroidApkToDownload(ApkType apkType)
{
return _androidApkVersionRepository.Exists(x => x.IsActive == IsActive.True);
return _androidApkVersionRepository.Exists(x => x.IsActive == IsActive.True && x.ApkType == apkType);
}
public Task<AndroidApkVersionInfo> GetLatestActiveInfo(ApkType apkType, int currentVersionCode)
{
var latest = _androidApkVersionRepository.GetLatestActive(apkType);
if (latest == null)
return Task.FromResult(new AndroidApkVersionInfo(0, "0", false, false, string.Empty, string.Empty));
// Return API endpoint for downloading APK file
var fileUrl = $"/api/android-apk/download?type={apkType}";
int latestCode = 0;
int.TryParse(latest.VersionCode, out latestCode);
var shouldUpdate = latestCode > currentVersionCode;
return Task.FromResult(new AndroidApkVersionInfo(latestCode, latest.VersionName, shouldUpdate, latest.IsForce, fileUrl, "Bug fixes and improvements"));
}
}

View File

@@ -5,7 +5,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ApkReader" Version="2.0.1.1" />
<PackageReference Include="AndroidXml" Version="1.1.24" />
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -123,7 +123,7 @@ namespace CompanyManagment.Application
result.LateToWorkDeduction, result.EarlyExitDeduction, result.RewardPay, result.SalaryAidDeduction, result.InstallmentDeduction, result.FineDeduction,
result.TaxDeduction, result.SumOfWorkingDays, result.TotalClaimsStr, result.TotalDeductionsStr, result.TotalPayment, contract?.ContractNo ?? "-",
fines, loanInstallments, salaryAids, rewards, result.LateToWorkValue, result.SettingSalary, result.DailyWage, result.ShiftStatus, result.IrregularShift, result.CustomizeRotatingShifts,
regularShift);
regularShift,result.DynamicDeductions);
_customizeCheckoutRepository.Create(entity);
@@ -187,7 +187,7 @@ namespace CompanyManagment.Application
computations.LateToWorkDeduction, computations.EarlyExitDeduction, computations.RewardPay, computations.SalaryAidDeduction, computations.InstallmentDeduction, computations.FineDeduction,
computations.TaxDeduction, computations.SumOfWorkingDays, computations.TotalClaimsStr, computations.TotalDeductionsStr, computations.TotalPayment, contract?.ContractNo ?? "-",
fines, loanInstallments, salaryAids, rewards, computations.LateToWorkValue, computations.SettingSalary, computations.DailyWage, computations.ShiftStatus, computations.IrregularShift,
computations.CustomizeRotatingShifts, regularShift);
computations.CustomizeRotatingShifts, regularShift,computations.DynamicDeductions);
_customizeCheckoutRepository.Create(entity);
_customizeCheckoutRepository.RemoveEmployeeCustomizeCheckoutInDates(command.WorkshopId, employeeId, command.ContractStart, command.ContractEnd);

View File

@@ -98,7 +98,7 @@ namespace CompanyManagment.Application
result.LateToWorkDeduction, result.EarlyExitDeduction, result.RewardPay, result.SalaryAidDeduction, result.InstallmentDeduction, result.FineDeduction,
result.TaxDeduction, result.SumOfWorkingDays, result.TotalClaimsStr, result.TotalDeductionsStr, result.TotalPayment, contract?.ContractNo ?? "-",
fines, loanInstallments, salaryAids, rewards, result.LateToWorkValue, result.SettingSalary, result.DailyWage, result.ShiftStatus, result.IrregularShift, result.CustomizeRotatingShifts,
regularShift);
regularShift,result.DynamicDeductions);
_customizeCheckoutTempRepository.Create(entity);
@@ -146,7 +146,8 @@ namespace CompanyManagment.Application
var regularShift = computations.EmployeeSettingsShifts.Select(x =>
new CustomizeCheckoutRegularShift(x.StartTime, x.EndTime, x.Placement)).ToList();
var entity = new CustomizeCheckoutTemp(command.ContractStart, command.ContractEnd, employeeId, employee.FName, employee.LName, employee.DateOfBirth, employee.NationalCode,
workshop.WorkshopFullName, command.WorkshopId, contract?.Id,
computations.MonthlySalary, computations.FridayPay, computations.OverTimePay, computations.BaseYearsPay,
@@ -155,7 +156,7 @@ namespace CompanyManagment.Application
computations.LateToWorkDeduction, computations.EarlyExitDeduction, computations.RewardPay, computations.SalaryAidDeduction, computations.InstallmentDeduction, computations.FineDeduction,
computations.TaxDeduction, computations.SumOfWorkingDays, computations.TotalClaimsStr, computations.TotalDeductionsStr, computations.TotalPayment, contract?.ContractNo ?? "-",
fines, loanInstallments, salaryAids, rewards, computations.LateToWorkValue, computations.SettingSalary, computations.DailyWage, computations.ShiftStatus, computations.IrregularShift,
computations.CustomizeRotatingShifts, regularShift);
computations.CustomizeRotatingShifts, regularShift,computations.DynamicDeductions);
_customizeCheckoutTempRepository.Create(entity);
_customizeCheckoutTempRepository.RemoveEmployeeTemporaryCheckoutInDates(command.WorkshopId, employeeId, command.ContractStart, command.ContractEnd);
}

View File

@@ -31,6 +31,7 @@ using Company.Domain.LeftWorkAgg;
using CompanyManagment.App.Contracts.Employee.DTO;
using Company.Domain.EmployeeAuthorizeTempAgg;
using Company.Domain.LeftWorkInsuranceAgg;
using _0_Framework.Application.FaceEmbedding;
namespace CompanyManagment.Application;
@@ -61,29 +62,31 @@ public class EmployeeAplication : RepositoryBase<long, Employee>, IEmployeeAppli
private readonly ICustomizeWorkshopGroupSettingsRepository _customizeWorkshopGroupSettingsRepository;
private readonly IEmployeeAuthorizeTempRepository _employeeAuthorizeTempRepository;
private readonly ILeftWorkInsuranceRepository _leftWorkInsuranceRepository;
private readonly IFaceEmbeddingService _faceEmbeddingService;
public EmployeeAplication(IEmployeeRepository employeeRepository, CompanyContext context, IWorkshopRepository workShopRepository, IWebHostEnvironment webHostEnvironment, IRollCallEmployeeStatusApplication rollCallEmployeeStatusApplication, IRollCallEmployeeRepository rollCallEmployeeRepository, ICustomizeWorkshopSettingsApplication customizeWorkshopSettingsApplication, IEmployeeDocumentsApplication employeeDocumentsApplication, IEmployeeDocumentsRepository employeeDocumentsRepository, IEmployeeBankInformationApplication employeeBankInformationApplication, ILeftWorkTempRepository leftWorkTempRepository, IUidService uidService, ICustomizeWorkshopEmployeeSettingsRepository customizeWorkshopEmployeeSettingsRepository, IPersonnelCodeRepository personnelCodeRepository, IEmployeeClientTempRepository employeeClientTempRepository, ICustomizeWorkshopGroupSettingsRepository customizeWorkshopGroupSettingsRepository, ILeftWorkRepository leftWorkRepository, IEmployeeAuthorizeTempRepository employeeAuthorizeTempRepository, ILeftWorkInsuranceRepository leftWorkInsuranceRepository) : base(context)
{
_context = context;
_WorkShopRepository = workShopRepository;
_webHostEnvironment = webHostEnvironment;
_rollCallEmployeeStatusApplication = rollCallEmployeeStatusApplication;
_rollCallEmployeeRepository = rollCallEmployeeRepository;
_customizeWorkshopSettingsApplication = customizeWorkshopSettingsApplication;
_employeeDocumentsApplication = employeeDocumentsApplication;
_employeeBankInformationApplication = employeeBankInformationApplication;
_leftWorkTempRepository = leftWorkTempRepository;
_uidService = uidService;
_customizeWorkshopEmployeeSettingsRepository = customizeWorkshopEmployeeSettingsRepository;
_personnelCodeRepository = personnelCodeRepository;
_employeeClientTempRepository = employeeClientTempRepository;
_leftWorkRepository = leftWorkRepository;
_employeeAuthorizeTempRepository = employeeAuthorizeTempRepository;
_leftWorkInsuranceRepository = leftWorkInsuranceRepository;
_EmployeeRepository = employeeRepository;
}
public EmployeeAplication(IEmployeeRepository employeeRepository, CompanyContext context, IWorkshopRepository workShopRepository, IWebHostEnvironment webHostEnvironment, IRollCallEmployeeStatusApplication rollCallEmployeeStatusApplication, IRollCallEmployeeRepository rollCallEmployeeRepository, ICustomizeWorkshopSettingsApplication customizeWorkshopSettingsApplication, IEmployeeDocumentsApplication employeeDocumentsApplication, IEmployeeDocumentsRepository employeeDocumentsRepository, IEmployeeBankInformationApplication employeeBankInformationApplication, ILeftWorkTempRepository leftWorkTempRepository, IUidService uidService, ICustomizeWorkshopEmployeeSettingsRepository customizeWorkshopEmployeeSettingsRepository, IPersonnelCodeRepository personnelCodeRepository, IEmployeeClientTempRepository employeeClientTempRepository, ICustomizeWorkshopGroupSettingsRepository customizeWorkshopGroupSettingsRepository, ILeftWorkRepository leftWorkRepository, IEmployeeAuthorizeTempRepository employeeAuthorizeTempRepository, ILeftWorkInsuranceRepository leftWorkInsuranceRepository, IFaceEmbeddingService faceEmbeddingService) : base(context)
{
_context = context;
_WorkShopRepository = workShopRepository;
_webHostEnvironment = webHostEnvironment;
_rollCallEmployeeStatusApplication = rollCallEmployeeStatusApplication;
_rollCallEmployeeRepository = rollCallEmployeeRepository;
_customizeWorkshopSettingsApplication = customizeWorkshopSettingsApplication;
_employeeDocumentsApplication = employeeDocumentsApplication;
_employeeBankInformationApplication = employeeBankInformationApplication;
_leftWorkTempRepository = leftWorkTempRepository;
_uidService = uidService;
_customizeWorkshopEmployeeSettingsRepository = customizeWorkshopEmployeeSettingsRepository;
_personnelCodeRepository = personnelCodeRepository;
_employeeClientTempRepository = employeeClientTempRepository;
_leftWorkRepository = leftWorkRepository;
_employeeAuthorizeTempRepository = employeeAuthorizeTempRepository;
_leftWorkInsuranceRepository = leftWorkInsuranceRepository;
_EmployeeRepository = employeeRepository;
_faceEmbeddingService = faceEmbeddingService;
}
public OperationResult Create(CreateEmployee command)
public OperationResult Create(CreateEmployee command)
{
var opration = new OperationResult();
if (_EmployeeRepository.Exists(x =>
@@ -1122,6 +1125,12 @@ public class EmployeeAplication : RepositoryBase<long, Employee>, IEmployeeAppli
rollCallEmployee.HasImage();
_rollCallEmployeeRepository.Create(rollCallEmployee);
_rollCallEmployeeRepository.SaveChanges();
string employeeFullName = employee.FName + " " + employee.LName;
var res = _faceEmbeddingService.GenerateEmbeddingsAsync(employee.id,command.WorkshopId,employeeFullName, filePath1,filePath2).GetAwaiter().GetResult();
if (!res.IsSuccedded)
{
return op.Failed(res.Message);
}
}
@@ -1576,7 +1585,12 @@ public class EmployeeAplication : RepositoryBase<long, Employee>, IEmployeeAppli
if (employee.IsAuthorized == false)
{
var apiResult = await _uidService.GetPersonalInfo(nationalCode, birthDate);
if (apiResult.ResponseContext.Status.Code == 14)
if (apiResult == null)
{
return op.Failed("این پرسنل در بانک اطلاعات موجود میباشد");
}
if (apiResult.ResponseContext.Status.Code is 14 or 3)
{
return op.Failed("این پرسنل در بانک اطلاعات موجود میباشد");
@@ -1635,8 +1649,13 @@ public class EmployeeAplication : RepositoryBase<long, Employee>, IEmployeeAppli
};
return op.Succcedded(data);
}
var apiResult = await _uidService.GetPersonalInfo(nationalCode, birthDate);
if (apiResult.ResponseContext.Status.Code == 14)
if (apiResult == null)
{
return op.Failed("سامانه احراز هویت در دسترس نمیباشد لطفا اطلاعات پرسنل را به صورت دستی وارد کنید", new EmployeeDataFromApiViewModel() { AuthorizedCanceled = true });
}
if (apiResult.ResponseContext.Status.Code is 14 or 3)
{
return op.Failed("سامانه احراز هویت در دسترس نمیباشد لطفا اطلاعات پرسنل را به صورت دستی وارد کنید", new EmployeeDataFromApiViewModel() { AuthorizedCanceled = true });

View File

@@ -1485,12 +1485,12 @@ public class EmployerApplication : IEmployerApplication
return opration.Failed("نام شرکت وارد شده تکراری است");
}
if (_EmployerRepository.Exists(x =>
x.RegisterId == command.RegisterId && !string.IsNullOrWhiteSpace(command.RegisterId) &&
x.RegisterId != null))
{
return opration.Failed(" شماره ثبت وارد شده تکراری است");
}
// if (_EmployerRepository.Exists(x =>
// x.RegisterId == command.RegisterId && !string.IsNullOrWhiteSpace(command.RegisterId) &&
// x.RegisterId != null))
// {
// return opration.Failed(" شماره ثبت وارد شده تکراری است");
// }
if (!string.IsNullOrEmpty(command.NationalId) && command.NationalId.Length != 11)
{

View File

@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Linq;
using _0_Framework.Application;
using _0_Framework.InfraStructure;
using Company.Domain.FinancialInvoiceAgg;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.EFCore;
namespace CompanyManagment.Application;
public class FinancialInvoiceApplication : RepositoryBase<long, FinancialInvoice>, IFinancialInvoiceApplication
{
private readonly IFinancialInvoiceRepository _financialInvoiceRepository;
private readonly CompanyContext _context;
public FinancialInvoiceApplication(IFinancialInvoiceRepository financialInvoiceRepository, CompanyContext context) : base(context)
{
_financialInvoiceRepository = financialInvoiceRepository;
_context = context;
}
public OperationResult Create(CreateFinancialInvoice command)
{
var operation = new OperationResult();
if (command.Amount <= 0)
return operation.Failed("مبلغ فاکتور باید بزرگتر از صفر باشد");
if (command.ContractingPartyId <= 0)
return operation.Failed("طرف قرارداد نامعتبر است");
if (string.IsNullOrWhiteSpace(command.Description))
return operation.Failed("توضیحات فاکتور الزامی است");
var financialInvoice = new FinancialInvoice(command.Amount, command.ContractingPartyId, command.Description);
if (command.Items != null && command.Items.Any())
{
foreach (var item in command.Items)
{
if (string.IsNullOrWhiteSpace(item.Description))
return operation.Failed("توضیحات آیتم الزامی است");
if (item.Amount <= 0)
return operation.Failed("مبلغ آیتم باید بزرگتر از صفر باشد");
var invoiceItem = new FinancialInvoiceItem(item.Description, item.Amount,
financialInvoice.id, item.Type, item.EntityId);
financialInvoice.AddItem(invoiceItem);
}
}
_financialInvoiceRepository.Create(financialInvoice);
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public OperationResult Edit(EditFinancialInvoice command)
{
var operation = new OperationResult();
var financialInvoice = _financialInvoiceRepository.Get(command.Id);
if (financialInvoice == null)
return operation.Failed("فاکتور مورد نظر یافت نشد");
if (financialInvoice.Status == FinancialInvoiceStatus.Paid)
return operation.Failed("امکان ویرایش فاکتور پرداخت شده وجود ندارد");
if (string.IsNullOrWhiteSpace(command.Description))
return operation.Failed("توضیحات فاکتور الزامی است");
// Update description
financialInvoice.Description = command.Description;
// Update items if provided
if (command.Items != null)
{
// Clear existing items
if (financialInvoice.Items != null)
{
financialInvoice.Items.Clear();
}
else
{
financialInvoice.SetItems([]);
}
// Add updated items
foreach (var item in command.Items)
{
if (string.IsNullOrWhiteSpace(item.Description))
return operation.Failed("توضیحات آیتم الزامی است");
if (item.Amount <= 0)
return operation.Failed("مبلغ آیتم باید بزرگتر از صفر باشد");
var invoiceItem = new FinancialInvoiceItem(item.Description, item.Amount,
financialInvoice.id, item.Type, item.EntityId);
financialInvoice.AddItem(invoiceItem);
}
}
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public OperationResult SetPaid(long id, DateTime paidAt)
{
var operation = new OperationResult();
var financialInvoice = _financialInvoiceRepository.Get(id);
if (financialInvoice == null)
return operation.Failed("فاکتور مورد نظر یافت نشد");
if (financialInvoice.Status == FinancialInvoiceStatus.Paid)
return operation.Failed("فاکتور قبلاً پرداخت شده است");
if (financialInvoice.Status == FinancialInvoiceStatus.Cancelled)
return operation.Failed("امکان پرداخت فاکتور لغو شده وجود ندارد");
financialInvoice.SetPaid(paidAt);
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public OperationResult SetUnpaid(long id)
{
var operation = new OperationResult();
var financialInvoice = _financialInvoiceRepository.Get(id);
if (financialInvoice == null)
return operation.Failed("فاکتور مورد نظر یافت نشد");
financialInvoice.SetUnpaid();
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public OperationResult SetCancelled(long id)
{
var operation = new OperationResult();
var financialInvoice = _financialInvoiceRepository.Get(id);
if (financialInvoice == null)
return operation.Failed("فاکتور مورد نظر یافت نشد");
if (financialInvoice.Status == FinancialInvoiceStatus.Paid)
return operation.Failed("امکان لغو فاکتور پرداخت شده وجود ندارد");
financialInvoice.SetCancelled();
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public OperationResult SetRefunded(long id)
{
var operation = new OperationResult();
var financialInvoice = _financialInvoiceRepository.Get(id);
if (financialInvoice == null)
return operation.Failed("فاکتور مورد نظر یافت نشد");
if (financialInvoice.Status != FinancialInvoiceStatus.Paid)
return operation.Failed("فقط فاکتورهای پرداخت شده قابل بازپرداخت هستند");
financialInvoice.SetRefunded();
_financialInvoiceRepository.SaveChanges();
return operation.Succcedded();
}
public EditFinancialInvoice GetDetails(long id)
{
return _financialInvoiceRepository.GetDetails(id);
}
public List<FinancialInvoiceViewModel> Search(FinancialInvoiceSearchModel searchModel)
{
return _financialInvoiceRepository.Search(searchModel);
}
//public OperationResult Remove(long id)
//{
// var operation = new OperationResult();
// try
// {
// var financialInvoice = _financialInvoiceRepository.Get(id);
// if (financialInvoice == null)
// return operation.Failed("فاکتور مورد نظر یافت نشد");
// if (financialInvoice.Status == FinancialInvoiceStatus.Paid)
// return operation.Failed("امکان حذف فاکتور پرداخت شده وجود ندارد");
// // Remove the entity using the context directly since Remove method might not be available
// _context.FinancialInvoiceSet.Remove(financialInvoice);
// _financialInvoiceRepository.SaveChanges();
// return operation.Succcedded();
// }
// catch (Exception ex)
// {
// return operation.Failed("خطا در حذف فاکتور");
// }
//}
}

View File

@@ -0,0 +1,132 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
namespace CompanyManagment.Application.Helpers
{
public class ApkInfo
{
public string VersionName { get; set; } = string.Empty;
public string VersionCode { get; set; } = string.Empty;
public string PackageName { get; set; } = string.Empty;
public string ApplicationLabel { get; set; } = string.Empty;
}
public static class ApkHelper
{
public static ApkInfo ReadApkInfo(Stream apkStream)
{
var apkInfo = new ApkInfo();
try
{
using var archive = new ZipArchive(apkStream, ZipArchiveMode.Read, true);
var manifestEntry = archive.GetEntry("AndroidManifest.xml");
if (manifestEntry == null)
{
throw new InvalidOperationException("AndroidManifest.xml not found in APK file");
}
using var manifestStream = manifestEntry.Open();
using var memoryStream = new MemoryStream();
manifestStream.CopyTo(memoryStream);
var manifestBytes = memoryStream.ToArray();
// Parse the binary AndroidManifest.xml
apkInfo = ParseBinaryManifest(manifestBytes);
// Validate that we found at least version information
if (string.IsNullOrEmpty(apkInfo.VersionCode) && string.IsNullOrEmpty(apkInfo.VersionName))
{
throw new InvalidOperationException("Could not extract version information from APK");
}
return apkInfo;
}
catch (Exception ex)
{
throw new InvalidOperationException($"Error reading APK file: {ex.Message}", ex);
}
}
private static ApkInfo ParseBinaryManifest(byte[] manifestBytes)
{
var apkInfo = new ApkInfo();
try
{
// Convert bytes to string for regex parsing
var text = System.Text.Encoding.UTF8.GetString(manifestBytes);
// Extract package name
var packageMatch = Regex.Match(text, @"package[^a-zA-Z]+([a-zA-Z][a-zA-Z0-9_]*(?:\.[a-zA-Z][a-zA-Z0-9_]*)+)", RegexOptions.IgnoreCase);
if (packageMatch.Success)
{
apkInfo.PackageName = packageMatch.Groups[1].Value;
}
// Extract version code - look for numeric values that could be version codes
var versionCodeMatch = Regex.Match(text, @"versionCode[^\d]*(\d+)", RegexOptions.IgnoreCase);
if (versionCodeMatch.Success)
{
apkInfo.VersionCode = versionCodeMatch.Groups[1].Value;
}
else
{
// Fallback: try to find reasonable numeric values
var numbers = Regex.Matches(text, @"\b(\d{1,8})\b");
foreach (Match numMatch in numbers)
{
if (int.TryParse(numMatch.Groups[1].Value, out int num) && num > 0 && num < 99999999)
{
apkInfo.VersionCode = num.ToString();
break;
}
}
}
// Extract version name
var versionNameMatch = Regex.Match(text, @"versionName[^\d]*(\d+(?:\.\d+)*(?:\.\d+)*)", RegexOptions.IgnoreCase);
if (versionNameMatch.Success)
{
apkInfo.VersionName = versionNameMatch.Groups[1].Value;
}
else
{
// Fallback: look for version-like patterns
var versionMatch = Regex.Match(text, @"\b(\d+\.\d+(?:\.\d+)*)\b");
if (versionMatch.Success)
{
apkInfo.VersionName = versionMatch.Groups[1].Value;
}
}
// Set defaults if nothing found
if (string.IsNullOrEmpty(apkInfo.VersionCode))
apkInfo.VersionCode = "1";
if (string.IsNullOrEmpty(apkInfo.VersionName))
apkInfo.VersionName = "1.0";
if (string.IsNullOrEmpty(apkInfo.PackageName))
apkInfo.PackageName = "unknown.package";
return apkInfo;
}
catch (Exception)
{
// Return default values if parsing fails
return new ApkInfo
{
VersionCode = "1",
VersionName = "1.0",
PackageName = "unknown.package"
};
}
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.SmsResultAgg;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.SmsResult;
namespace CompanyManagment.Application;
public class SmsSettingApplication : ISmsSettingApplication
{
private readonly ISmsSettingsRepository _smsSettingsRepository;
private readonly IInstitutionContractRepository _institutionContractRepository;
public SmsSettingApplication(ISmsSettingsRepository smsSettingsRepository, IInstitutionContractRepository institutionContractRepository)
{
_smsSettingsRepository = smsSettingsRepository;
_institutionContractRepository = institutionContractRepository;
}
public async Task<SmsSettingViewModel> GetSmsSettingsByType(TypeOfSmsSetting typeOfSmsSetting)
{
return await _smsSettingsRepository.GetSmsSettingsByType(typeOfSmsSetting);
}
/// <summary>
/// ایجاد تنظیمات پیامک یادآور
/// </summary>
/// <param name="dayOfMonth"></param>
/// <param name="timeOfDay"></param>
/// <param name="typeOfSmsSetting"></param>
/// <returns></returns>
public async Task<OperationResult> CreateSmsSetting(int dayOfMonth, string timeOfDay,
TypeOfSmsSetting typeOfSmsSetting)
{
var op = new OperationResult();
var timeSpan = new TimeSpan();
if (string.IsNullOrWhiteSpace(timeOfDay))
return op.Failed("ساعت وارد نشده است");
try
{
timeSpan = TimeSpan.ParseExact(timeOfDay, @"hh\:mm", null);
}
catch (Exception e)
{
return op.Failed("فرمت ساعت اشتباه است");
}
if (dayOfMonth < 1 || dayOfMonth > 31)
{
return op.Failed("عدد روز می بایست بین 1 تا 31 باشد");
}
if (_smsSettingsRepository.Exists(x => x.DayOfMonth == dayOfMonth && x.TimeOfDay == timeSpan && x.TypeOfSmsSetting == typeOfSmsSetting))
return op.Failed("رکورد ایجاد شده تکراری است");
var create = new SmsSetting(typeOfSmsSetting, dayOfMonth, timeSpan);
await _smsSettingsRepository.CreateAsync(create);
await _smsSettingsRepository.SaveChangesAsync();
return op.Succcedded();
}
public async Task<EditSmsSetting> GetSmsSettingToEdit(long id)
{
return await _smsSettingsRepository.GetSmsSettingToEdit(id);
}
public async Task<OperationResult> EditeSmsSetting(EditSmsSetting command)
{
var op = new OperationResult();
var timeSpan = new TimeSpan();
if (string.IsNullOrWhiteSpace(command.TimeOfDayDisplay))
return op.Failed("ساعت وارد نشده است");
try
{
timeSpan = TimeSpan.ParseExact(command.TimeOfDayDisplay, @"hh\:mm", null);
}
catch (Exception e)
{
return op.Failed("فرمت ساعت اشتباه است");
}
if (command.DayOfMonth < 1 || command.DayOfMonth > 31)
{
return op.Failed("عدد روز می بایست بین 1 تا 31 باشد");
}
if (_smsSettingsRepository.Exists(x => x.DayOfMonth == command.DayOfMonth && x.TimeOfDay == timeSpan && x.TypeOfSmsSetting == command.TypeOfSmsSetting && x.id != command.Id))
return op.Failed("رکورد ایجاد شده تکراری است");
var editSmsSetting = _smsSettingsRepository.Get(command.Id);
editSmsSetting.Edit(command.DayOfMonth, timeSpan);
await _smsSettingsRepository.SaveChangesAsync();
return op.Succcedded();
}
public async Task RemoveSetting(long id)
{
await _smsSettingsRepository.RemoveItem(id);
}
public async Task<List<SmsListData>> GetSmsListData(TypeOfSmsSetting typeOfSmsSetting)
{
return await _institutionContractRepository.GetSmsListData(DateTime.Now, typeOfSmsSetting);
}
public async Task<List<BlockSmsListData>> GetBlockSmsListData(TypeOfSmsSetting typeOfSmsSetting)
{
return await _institutionContractRepository.GetBlockListData(DateTime.Now);
}
public async Task<OperationResult> InstantSendReminderSms(List<SmsListData> command)
{
var op = new OperationResult();
string typeOfSms = "یادآور بدهی ماهانه";
string sendMessStart = "شروع یادآور آنی";
string sendMessEnd = "پایان یادآور آنی";
if (command.Any())
{
await _institutionContractRepository.SendReminderSmsToContractingParties(command, typeOfSms, sendMessStart, sendMessEnd);
return op.Succcedded();
}
else
{
return op.Failed("موردی انتخاب نشده است");
}
}
public async Task<OperationResult> InstantSendBlockSms(List<BlockSmsListData> command)
{
var op = new OperationResult();
string typeOfSms = "اعلام مسدودی طرف حساب";
string sendMessStart = "شروع مسدودی آنی";
string sendMessEnd = "پایان مسدودی آنی ";
if (command.Any())
{
await _institutionContractRepository.SendBlockSmsToContractingParties(command, typeOfSms, sendMessStart,
sendMessEnd);
return op.Succcedded();
}
else
{
return op.Failed("موردی انتخاب نشده است");
}
}
}

View File

@@ -119,27 +119,29 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati
//دریافت اطلاعات احراز هویت
var apiResponsParty = await _uidService.GetPersonalInfo(nationalCode, dateOfBirth);
//چک کردن مطابقت شماره همراه و کد ملی
var isMachMobilAndNationalCode = await _uidService.IsMachPhoneWithNationalCode(nationalCode, mobile);
if (isMachMobilAndNationalCode == null)
return op.Failed("خطا در سرویس احراز هویت");
if (!isMachMobilAndNationalCode.IsMatched)
return op.Failed("شماره همراه وارد شده با کد ملی مطابقت ندارد");
if (apiResponsParty == null)
throw new InternalServerException("خطا در سرویس احراز هویت");
if (apiResponsParty.ResponseContext.Status.Code ==14)
if (apiResponsParty.ResponseContext.Status.Code is 14 or 3)
throw new InternalServerException("سیستم احراز هویت در دسترس نمی باشد");
if (apiResponsParty.ResponseContext.Status.Code != 0)
return op.Failed($"{apiResponsParty.ResponseContext.Status.Message}");
idNumberParty = apiResponsParty.IdentificationInformation.ShenasnamehNumber == "0"
idNumberParty = apiResponsParty.IdentificationInformation.ShenasnamehNumber == "0"
? apiResponsParty.IdentificationInformation.NationalId
: apiResponsParty.IdentificationInformation.ShenasnamehNumber;
//چک کردن مطابقت شماره همراه و کد ملی
var isMachMobilAndNationalCode = await _uidService.IsMachPhoneWithNationalCode(nationalCode, mobile);
if (isMachMobilAndNationalCode == null)
throw new InternalServerException("خطا در سرویس تطابق کد ملی و شماره همراه");
if (!isMachMobilAndNationalCode.IsMatched)
return op.Failed("شماره همراه وارد شده با کد ملی مطابقت ندارد");
contractingParty.Authentication(apiResponsParty.BasicInformation.FirstName, apiResponsParty.BasicInformation.LastName,
apiResponsParty.BasicInformation.FatherName,idNumberParty,apiResponsParty.IdentificationInformation.ShenasnameSeri,
apiResponsParty.IdentificationInformation.ShenasnameSerial,dateOfBirth,apiResponsParty.BasicInformation.GenderEnum,
@@ -147,12 +149,11 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati
await _contractingPartyTempRepository.SaveChangesAsync();
}
if (contractingParty.Phone != mobile)
return op.Failed("شما قبلا با شماره همراه دیگری احراز هویت شده اید");
result.Id = contractingParty.id;
result.FName = contractingParty.FName;
result.LName = contractingParty.LName;
@@ -206,9 +207,14 @@ public class TemporaryClientRegistrationApplication : ITemporaryClientRegistrati
if (apiRespons == null)
throw new InternalServerException("خطا در سرویس احراز هویت");
if (apiRespons.ResponseContext.Status.Code == 14)
if (apiRespons.ResponseContext.Status.Code is 14 or 3)
throw new InternalServerException("سیستم احراز هویت در دسترس نمی باشد");
if (apiRespons.ResponseContext.Status.Code == 2)
{
throw new InternalServerException("سیستم احراز هویت در دسترس نمی باشد");
}
if (apiRespons.ResponseContext.Status.Code != 0)
return op.Failed($"{apiRespons.ResponseContext.Status.Message}");

View File

@@ -45,6 +45,7 @@ using Company.Domain.FileEmployerAgg;
using Company.Domain.FileState;
using Company.Domain.FileTiming;
using Company.Domain.FileTitle;
using Company.Domain.FinancialInvoiceAgg;
using Company.Domain.FinancialStatmentAgg;
using Company.Domain.FinancialTransactionAgg;
using Company.Domain.FineAgg;
@@ -162,6 +163,12 @@ public class CompanyContext : DbContext
//-------Main-Project----------------------------
#region SmsSettings
public DbSet<SmsSetting> SmsSettings { get; set; }
#endregion
#region Mahan
//-----------------------------RollCallWorkshopSettings-----------------------------
@@ -204,12 +211,13 @@ public class CompanyContext : DbContext
public DbSet<AuthorizedBankDetails> AuthorizedBankDetails { get; set; }
#endregion
public DbSet<FinancialInvoice> FinancialInvoices { get; set; }
#region Pooya
#endregion
public DbSet<EmployeeDocumentItem> EmployeeDocumentItems { get; set; }
#region Pooya
public DbSet<EmployeeDocumentItem> EmployeeDocumentItems { get; set; }
public DbSet<EmployeeDocuments> EmployeeDocuments { get; set; }
public DbSet<WorkshopSubAccount> WorkshopSubAccounts { get; set; }

View File

@@ -1,9 +1,8 @@
using Company.Domain.AndroidApkVersionAgg;
using Company.Domain.AndroidApkVersionAgg;
using CompanyManagment.App.Contracts.AndroidApkVersion;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using Microsoft.AspNetCore.Hosting.Builder;
using _0_Framework.Application;
namespace CompanyManagment.EFCore.Mapping;
@@ -19,10 +18,15 @@ public class AndroidApkVersionMapping:IEntityTypeConfiguration<AndroidApkVersion
v => v.ToString(),
v => (IsActive)Enum.Parse(typeof(IsActive), v)).HasMaxLength(5);
builder.Property(x => x.Title).HasMaxLength(50);
builder.Property(x => x.ApkType).HasConversion(
v => v.ToString(),
v => (ApkType)Enum.Parse(typeof(ApkType), v)).HasMaxLength(20);
builder.Property(x => x.Title).HasMaxLength(200);
builder.Property(x => x.VersionCode).HasMaxLength(20);
builder.Property(x => x.VersionName).HasMaxLength(35);
builder.Property(x => x.Path).HasMaxLength(255);
builder.Property(x => x.IsForce);
}
}

View File

@@ -131,5 +131,12 @@ public class CustomizeCheckoutMapping : IEntityTypeConfiguration<CustomizeChecko
// .HasForeignKey(x => x.EmployeeId);
#endregion
builder.OwnsMany(x => x.CheckoutDynamicDeductions, dynamicDeduction =>
{
dynamicDeduction.Property(x => x.Name).HasMaxLength(100);
dynamicDeduction.Property(x => x.Count);
dynamicDeduction.Property(x => x.Amount).HasMaxLength(30);
});
}
}

View File

@@ -129,5 +129,12 @@ public class CustomizeCheckoutTempMapping : IEntityTypeConfiguration<CustomizeCh
// .HasForeignKey(x => x.EmployeeId);
#endregion
builder.OwnsMany(x => x.CheckoutDynamicDeductions, dynamicDeduction =>
{
dynamicDeduction.Property(x => x.Name).HasMaxLength(100);
dynamicDeduction.Property(x => x.Count);
dynamicDeduction.Property(x => x.Amount).HasMaxLength(30);
});
}
}

View File

@@ -0,0 +1,17 @@
using Company.Domain.FinancialInvoiceAgg;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CompanyManagment.EFCore.Mapping;
public class FinancialInvoiceItemMapping : IEntityTypeConfiguration<FinancialInvoiceItem>
{
public void Configure(EntityTypeBuilder<FinancialInvoiceItem> builder)
{
builder.Property(x=>x.Description).HasMaxLength(800);
builder.Property(x => x.Type).HasConversion<string>().HasMaxLength(50);
builder.HasOne(x => x.FinancialInvoice).WithMany(x => x.Items)
.HasForeignKey(x => x.FinancialInvoiceId);
}
}

View File

@@ -0,0 +1,25 @@
using Company.Domain.FinancialInvoiceAgg;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CompanyManagment.EFCore.Mapping;
public class FinancialInvoiceMapping:IEntityTypeConfiguration<FinancialInvoice>
{
public void Configure(EntityTypeBuilder<FinancialInvoice> builder)
{
builder.HasKey(x => x.id);
builder.Property(x => x.Status).HasConversion<string>().HasMaxLength(20);
builder.Property(x => x.PaidAt).IsRequired(false);
builder.Property(x => x.Description).HasMaxLength(800);
builder.Property(x => x.InvoiceNumber).HasMaxLength(22);
builder.HasMany(x => x.Items).WithOne(x => x.FinancialInvoice)
.HasForeignKey(x => x.FinancialInvoiceId).IsRequired().OnDelete(DeleteBehavior.Cascade);
builder.HasMany(x => x.PaymentTransactions).WithOne(x => x.FinancialInvoice)
.HasForeignKey(x => x.FinancialInvoiceId).IsRequired(false).OnDelete(DeleteBehavior.NoAction);
}
}

View File

@@ -14,7 +14,7 @@ public class FinancialTransactionMapping : IEntityTypeConfiguration<FinancialTra
builder.Property(x => x.TdateFa);
builder.Property(x => x.TdateFa).HasMaxLength(10);
builder.Property(x => x.TypeOfTransaction).HasMaxLength(10);
builder.Property(x => x.DescriptionOption).HasMaxLength(50);
builder.Property(x => x.DescriptionOption).HasMaxLength(100);
builder.Property(x => x.Description).HasMaxLength(600);
builder.Property(x => x.Deptor);
builder.Property(x => x.Creditor);

View File

@@ -11,7 +11,7 @@ public class InstitutinContractContactInfoMapping : IEntityTypeConfiguration<Ins
builder.ToTable("InstitutinContractContactInfo");
builder.HasKey(x => x.id);
builder.Property(x => x.FnameLname).HasMaxLength(50);
builder.Property(x => x.FnameLname).HasMaxLength(150);
builder.Property(x => x.PhoneNumber).HasMaxLength(20);
builder.Property(x => x.PhoneType).HasMaxLength(20);
builder.Property(x => x.Position).HasMaxLength(50);

View File

@@ -14,8 +14,8 @@ public class PersonalContractingpartyMapping : IEntityTypeConfiguration<Personal
builder.HasKey(x => x.id);
//builder.Property(x => x.LegalName).HasMaxLength(255).IsRequired();
builder.Property(x => x.FName).HasMaxLength(50).IsRequired();
builder.Property(x => x.LName).HasMaxLength(50).IsRequired();
builder.Property(x => x.FName).HasMaxLength(150).IsRequired();
builder.Property(x => x.LName).HasMaxLength(150).IsRequired();
builder.Property(x => x.SureName).HasMaxLength(50).IsRequired(false);
builder.Property(x => x.Nationalcode).HasMaxLength(10).IsRequired();
builder.Property(x => x.IdNumber).HasMaxLength(20).IsRequired(false);

View File

@@ -0,0 +1,30 @@
using System;
using _0_Framework.Application.Enums;
using Company.Domain.SmsResultAgg;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CompanyManagment.EFCore.Mapping;
public class SmsSettingMapping : IEntityTypeConfiguration<SmsSetting>
{
public void Configure(EntityTypeBuilder<SmsSetting> builder)
{
builder.ToTable("SmsSettings");
builder.HasKey(x => x.id);
builder.Property(x => x.DayOfMonth)
.IsRequired();
builder.Property(x => x.TimeOfDay)
.HasColumnType("time(0)")
.IsRequired();
builder.Property(x => x.TypeOfSmsSetting).HasConversion(
v => v.ToString(),
v => (TypeOfSmsSetting)Enum.Parse(typeof(TypeOfSmsSetting), v)).HasMaxLength(70);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CompanyManagment.EFCore.Migrations
{
/// <inheritdoc />
public partial class AddfinancialInvoiceTable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "FinancialInvoice",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Month = table.Column<int>(type: "int", nullable: false),
Year = table.Column<int>(type: "int", nullable: false),
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
PaidAt = table.Column<DateTime>(type: "datetime2", nullable: true),
Amount = table.Column<double>(type: "float", nullable: false),
SmsCode = table.Column<string>(type: "nvarchar(122)", maxLength: 122, nullable: true),
FinancialStatementId = table.Column<long>(type: "bigint", nullable: true),
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FinancialInvoice", x => x.id);
table.ForeignKey(
name: "FK_FinancialInvoice_FinancialStatments_FinancialStatementId",
column: x => x.FinancialStatementId,
principalTable: "FinancialStatments",
principalColumn: "id");
});
migrationBuilder.CreateIndex(
name: "IX_FinancialInvoice_FinancialStatementId",
table: "FinancialInvoice",
column: "FinancialStatementId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "FinancialInvoice");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,226 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CompanyManagment.EFCore.Migrations
{
/// <inheritdoc />
public partial class addfinancialinvoice : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_FinancialInvoice_FinancialStatments_FinancialStatementId",
table: "FinancialInvoice");
migrationBuilder.DropPrimaryKey(
name: "PK_FinancialInvoice",
table: "FinancialInvoice");
migrationBuilder.DropColumn(
name: "Month",
table: "FinancialInvoice");
migrationBuilder.DropColumn(
name: "SmsCode",
table: "FinancialInvoice");
migrationBuilder.DropColumn(
name: "Year",
table: "FinancialInvoice");
migrationBuilder.RenameTable(
name: "FinancialInvoice",
newName: "FinancialInvoices");
migrationBuilder.RenameColumn(
name: "FinancialStatementId",
table: "FinancialInvoices",
newName: "FinancialStatmentid");
migrationBuilder.RenameIndex(
name: "IX_FinancialInvoice_FinancialStatementId",
table: "FinancialInvoices",
newName: "IX_FinancialInvoices_FinancialStatmentid");
migrationBuilder.AddColumn<long>(
name: "FinancialInvoiceId",
table: "PaymentTransactions",
type: "bigint",
nullable: true);
migrationBuilder.AddColumn<long>(
name: "ContractingPartyId",
table: "FinancialInvoices",
type: "bigint",
nullable: false,
defaultValue: 0L);
migrationBuilder.AddColumn<string>(
name: "Description",
table: "FinancialInvoices",
type: "nvarchar(800)",
maxLength: 800,
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsActive",
table: "FinancialInvoices",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<Guid>(
name: "PublicId",
table: "FinancialInvoices",
type: "uniqueidentifier",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddPrimaryKey(
name: "PK_FinancialInvoices",
table: "FinancialInvoices",
column: "id");
migrationBuilder.CreateTable(
name: "FinancialInvoiceItem",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Description = table.Column<string>(type: "nvarchar(800)", maxLength: 800, nullable: true),
Amount = table.Column<double>(type: "float", nullable: false),
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
EntityId = table.Column<long>(type: "bigint", nullable: false),
FinancialInvoiceId = table.Column<long>(type: "bigint", nullable: false),
CreationDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FinancialInvoiceItem", x => x.id);
table.ForeignKey(
name: "FK_FinancialInvoiceItem_FinancialInvoices_FinancialInvoiceId",
column: x => x.FinancialInvoiceId,
principalTable: "FinancialInvoices",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_PaymentTransactions_FinancialInvoiceId",
table: "PaymentTransactions",
column: "FinancialInvoiceId");
migrationBuilder.CreateIndex(
name: "IX_FinancialInvoiceItem_FinancialInvoiceId",
table: "FinancialInvoiceItem",
column: "FinancialInvoiceId");
migrationBuilder.AddForeignKey(
name: "FK_FinancialInvoices_FinancialStatments_FinancialStatmentid",
table: "FinancialInvoices",
column: "FinancialStatmentid",
principalTable: "FinancialStatments",
principalColumn: "id");
migrationBuilder.AddForeignKey(
name: "FK_PaymentTransactions_FinancialInvoices_FinancialInvoiceId",
table: "PaymentTransactions",
column: "FinancialInvoiceId",
principalTable: "FinancialInvoices",
principalColumn: "id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_FinancialInvoices_FinancialStatments_FinancialStatmentid",
table: "FinancialInvoices");
migrationBuilder.DropForeignKey(
name: "FK_PaymentTransactions_FinancialInvoices_FinancialInvoiceId",
table: "PaymentTransactions");
migrationBuilder.DropTable(
name: "FinancialInvoiceItem");
migrationBuilder.DropIndex(
name: "IX_PaymentTransactions_FinancialInvoiceId",
table: "PaymentTransactions");
migrationBuilder.DropPrimaryKey(
name: "PK_FinancialInvoices",
table: "FinancialInvoices");
migrationBuilder.DropColumn(
name: "FinancialInvoiceId",
table: "PaymentTransactions");
migrationBuilder.DropColumn(
name: "ContractingPartyId",
table: "FinancialInvoices");
migrationBuilder.DropColumn(
name: "Description",
table: "FinancialInvoices");
migrationBuilder.DropColumn(
name: "IsActive",
table: "FinancialInvoices");
migrationBuilder.DropColumn(
name: "PublicId",
table: "FinancialInvoices");
migrationBuilder.RenameTable(
name: "FinancialInvoices",
newName: "FinancialInvoice");
migrationBuilder.RenameColumn(
name: "FinancialStatmentid",
table: "FinancialInvoice",
newName: "FinancialStatementId");
migrationBuilder.RenameIndex(
name: "IX_FinancialInvoices_FinancialStatmentid",
table: "FinancialInvoice",
newName: "IX_FinancialInvoice_FinancialStatementId");
migrationBuilder.AddColumn<int>(
name: "Month",
table: "FinancialInvoice",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "SmsCode",
table: "FinancialInvoice",
type: "nvarchar(122)",
maxLength: 122,
nullable: true);
migrationBuilder.AddColumn<int>(
name: "Year",
table: "FinancialInvoice",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddPrimaryKey(
name: "PK_FinancialInvoice",
table: "FinancialInvoice",
column: "id");
migrationBuilder.AddForeignKey(
name: "FK_FinancialInvoice_FinancialStatments_FinancialStatementId",
table: "FinancialInvoice",
column: "FinancialStatementId",
principalTable: "FinancialStatments",
principalColumn: "id");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CompanyManagment.EFCore.Migrations
{
/// <inheritdoc />
public partial class SmsSettingsTable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SmsSettings",
columns: table => new
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
TypeOfSmsSetting = table.Column<string>(type: "nvarchar(30)", maxLength: 30, nullable: false),
DayOfMonth = table.Column<int>(type: "int", nullable: false),
TimeOfDay = table.Column<TimeSpan>(type: "time(0)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SmsSettings", x => x.id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SmsSettings");
}
}
}

Some files were not shown because too many files have changed in this diff Show More