Compare commits
113 Commits
5ad2a795b8
...
3a37cfdf37
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a37cfdf37 | |||
| 4282966afd | |||
| 03b62cd27b | |||
| ff2b33a66d | |||
| 85b327d0c4 | |||
| da797b2208 | |||
| 8ef654ad2e | |||
| 738d1e6a0a | |||
| 56645ff40f | |||
| 193add07e1 | |||
| bd969616ad | |||
| c2ddd6097c | |||
| b5707ba133 | |||
| a0cc285d6f | |||
| 10df95c481 | |||
| 5908b54312 | |||
| 6b80c3bfeb | |||
| 8820483584 | |||
| 93e1b13f54 | |||
| dff77aa22f | |||
| 75cb4557e4 | |||
| e9157d7985 | |||
| 86ebc95ada | |||
| b0aefdc93a | |||
| f6685a1ca5 | |||
| fd14670914 | |||
| b161ed7c15 | |||
|
|
e4a611ccc2 | ||
| cc06c2dfc4 | |||
| 29fa0e87d1 | |||
| 852124d971 | |||
| 45897b99cb | |||
| 7ae001e277 | |||
| b7a9d6148d | |||
| 244a6cc547 | |||
| 4cebaba540 | |||
|
|
040e9c311b | ||
| 62734fc583 | |||
| 20efab871a | |||
| 39224c7ed7 | |||
| 2119171291 | |||
| 2339384b5e | |||
| 02a7791041 | |||
| c00d1a5451 | |||
| e917ff3e9c | |||
| cd091eda56 | |||
| aa6df0f803 | |||
| 2e64f4de32 | |||
|
|
8c9ce52ec2 | ||
| 635654890e | |||
| fbfd04c898 | |||
| 92e6942437 | |||
| 04216791f7 | |||
| 0b308c776b | |||
| 6704e168c3 | |||
| 70c9d4bb3d | |||
| 3b1b6e9d89 | |||
| a31b4b73ab | |||
| 0973e722fb | |||
| f1e3febfb0 | |||
| 3ab215b401 | |||
| e6f8cc626b | |||
| cedf3d19b5 | |||
| b4cffbf713 | |||
| f18b1f8dea | |||
| c78c9a92b4 | |||
| 3f0d6f26fc | |||
| ec72632004 | |||
|
|
4060d7d1f2 | ||
| 12a1e1cf27 | |||
| ca561711de | |||
| acffebfb90 | |||
| f785003e9b | |||
|
|
f7dce83629 | ||
| df1408b63a | |||
| 77306c6bdb | |||
| 7660063ac3 | |||
| ebc4a1e071 | |||
| f1c6468e47 | |||
| ae20e215db | |||
| b9b06ba54c | |||
| ba38c857a2 | |||
| f42ebe3886 | |||
| 85d7863fb2 | |||
| 9709893603 | |||
| 922eb7bc0d | |||
| de324407d0 | |||
| 9247221a9f | |||
| 4b4ebee1a1 | |||
| 49ddd3ec45 | |||
| 8ab737fe8a | |||
| 7f5f3da5fb | |||
| 684598eb6b | |||
|
|
adc31a6909 | ||
| b3d4018c5f | |||
| 84b1e7de0b | |||
| 783c6576de | |||
| 66b8a74873 | |||
| c2bdf76957 | |||
| a8b935946a | |||
|
|
40c0bcd3ca | ||
| bba751256e | |||
| bb8c314723 | |||
| 07bec97973 | |||
| ba486cffd8 | |||
| 260ea2214d | |||
| c85c6f4df5 | |||
| 2cb283f1cd | |||
| ba92a3b3ed | |||
| 2f3203c524 | |||
| b479c7cf19 | |||
| e73d3e0744 | |||
| 98409f5b87 |
@ -7,6 +7,7 @@ using Marco.Pms.Model.DocumentManager;
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.Entitlements;
|
using Marco.Pms.Model.Entitlements;
|
||||||
using Marco.Pms.Model.Forum;
|
using Marco.Pms.Model.Forum;
|
||||||
|
using Marco.Pms.Model.Mail;
|
||||||
using Marco.Pms.Model.Master;
|
using Marco.Pms.Model.Master;
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Projects;
|
||||||
using Marco.Pms.Model.Roles;
|
using Marco.Pms.Model.Roles;
|
||||||
@ -29,53 +30,30 @@ namespace Marco.Pms.DataAccess.Data
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<RefreshToken> RefreshTokens { get; set; }
|
public DbSet<RefreshToken> RefreshTokens { get; set; }
|
||||||
|
|
||||||
public DbSet<Tenant> Tenants { get; set; }
|
public DbSet<Tenant> Tenants { get; set; }
|
||||||
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
|
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
|
||||||
|
|
||||||
public DbSet<ActivityMaster> ActivityMasters { get; set; }
|
public DbSet<ActivityMaster> ActivityMasters { get; set; }
|
||||||
public DbSet<Project> Projects { get; set; }
|
public DbSet<Project> Projects { get; set; }
|
||||||
public DbSet<ProjectAllocation> ProjectAllocations { get; set; }
|
public DbSet<ProjectAllocation> ProjectAllocations { get; set; }
|
||||||
|
|
||||||
public DbSet<StatusMaster> StatusMasters { get; set; }
|
public DbSet<StatusMaster> StatusMasters { get; set; }
|
||||||
|
|
||||||
public DbSet<Building> Buildings { get; set; }
|
public DbSet<Building> Buildings { get; set; }
|
||||||
public DbSet<Floor> Floor { get; set; }
|
public DbSet<Floor> Floor { get; set; }
|
||||||
|
|
||||||
public DbSet<WorkArea> WorkAreas { get; set; }
|
public DbSet<WorkArea> WorkAreas { get; set; }
|
||||||
public DbSet<WorkItem> WorkItems { get; set; }
|
public DbSet<WorkItem> WorkItems { get; set; }
|
||||||
//public DbSet<WorkItemMapping> WorkItemMapping { get; set; }
|
|
||||||
|
|
||||||
public DbSet<WorkShift> WorkShifts { get; set; }
|
public DbSet<WorkShift> WorkShifts { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public DbSet<TaskAllocation> TaskAllocations { get; set; }
|
public DbSet<TaskAllocation> TaskAllocations { get; set; }
|
||||||
public DbSet<TaskComment> TaskComments { get; set; }
|
public DbSet<TaskComment> TaskComments { get; set; }
|
||||||
public DbSet<TaskMembers> TaskMembers { get; set; }
|
public DbSet<TaskMembers> TaskMembers { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// public DbSet<Attendance> Attendances { get; set; }
|
|
||||||
public DbSet<Attendance> Attendes { get; set; }
|
public DbSet<Attendance> Attendes { get; set; }
|
||||||
|
|
||||||
public DbSet<AttendanceLog> AttendanceLogs { get; set; }
|
public DbSet<AttendanceLog> AttendanceLogs { get; set; }
|
||||||
// public DbSet<AttendLog> AttendLogs { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public DbSet<Employee> Employees { get; set; }
|
public DbSet<Employee> Employees { get; set; }
|
||||||
public DbSet<EmployeeRoleMapping> EmployeeRoleMappings { get; set; }
|
public DbSet<EmployeeRoleMapping> EmployeeRoleMappings { get; set; }
|
||||||
|
|
||||||
public DbSet<Module> Modules { get; set; }
|
public DbSet<Module> Modules { get; set; }
|
||||||
public DbSet<Feature> Features { get; set; }
|
public DbSet<Feature> Features { get; set; }
|
||||||
public DbSet<FeaturePermission> FeaturePermissions { get; set; }
|
public DbSet<FeaturePermission> FeaturePermissions { get; set; }
|
||||||
|
|
||||||
public DbSet<ApplicationRole> ApplicationRoles { get; set; }
|
public DbSet<ApplicationRole> ApplicationRoles { get; set; }
|
||||||
public DbSet<JobRole> JobRoles { get; set; }
|
public DbSet<JobRole> JobRoles { get; set; }
|
||||||
public DbSet<RolePermissionMappings> RolePermissionMappings { get; set; }
|
public DbSet<RolePermissionMappings> RolePermissionMappings { get; set; }
|
||||||
|
|
||||||
public DbSet<Industry> Industries { get; set; }
|
public DbSet<Industry> Industries { get; set; }
|
||||||
public DbSet<ActivityCheckList> ActivityCheckLists { get; set; }
|
public DbSet<ActivityCheckList> ActivityCheckLists { get; set; }
|
||||||
public DbSet<CheckListMappings> CheckListMappings { get; set; }
|
public DbSet<CheckListMappings> CheckListMappings { get; set; }
|
||||||
@ -103,6 +81,10 @@ namespace Marco.Pms.DataAccess.Data
|
|||||||
public DbSet<DirectoryUpdateLog> DirectoryUpdateLogs { get; set; }
|
public DbSet<DirectoryUpdateLog> DirectoryUpdateLogs { get; set; }
|
||||||
public DbSet<ContactProjectMapping> ContactProjectMappings { get; set; }
|
public DbSet<ContactProjectMapping> ContactProjectMappings { get; set; }
|
||||||
|
|
||||||
|
public DbSet<MailingList> MailingList { get; set; }
|
||||||
|
public DbSet<MailDetails> MailDetails { get; set; }
|
||||||
|
public DbSet<MailLog> MailLogs { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
|||||||
2581
Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs
generated
Normal file
2581
Marco.Pms.DataAccess/Migrations/20250530055939_Added_Mail_Related_Tables.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_Mail_Related_Tables : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "MailingList",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
Title = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Body = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Keywords = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_MailingList", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "MailLogs",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
ProjectId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
Body = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
EmailId = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
TimeStamp = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
EmployeeId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_MailLogs", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "MailDetails",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
ProjectId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
Recipient = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Subject = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Schedule = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
MailListId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
|
||||||
|
TenantId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_MailDetails", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_MailDetails_MailingList_MailListId",
|
||||||
|
column: x => x.MailListId,
|
||||||
|
principalTable: "MailingList",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MailDetails_MailListId",
|
||||||
|
table: "MailDetails",
|
||||||
|
column: "MailListId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "MailDetails");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "MailLogs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "MailingList");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1240,6 +1240,97 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<Guid>("MailListId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Recipient")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Schedule")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Subject")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid>("TenantId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MailListId");
|
||||||
|
|
||||||
|
b.ToTable("MailDetails");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.Mail.MailLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Body")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("EmailId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid?>("EmployeeId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<Guid>("TenantId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeStamp")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("MailLogs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.Mail.MailingList", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Body")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Keywords")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid>("TenantId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("MailingList");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b =>
|
modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@ -2794,6 +2885,17 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Navigation("Ticket");
|
b.Navigation("Ticket");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Marco.Pms.Model.Mail.MailDetails", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Marco.Pms.Model.Mail.MailingList", "MailBody")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("MailListId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("MailBody");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b =>
|
modelBuilder.Entity("Marco.Pms.Model.Master.ActivityMaster", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant")
|
b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant")
|
||||||
|
|||||||
@ -30,21 +30,15 @@
|
|||||||
|
|
||||||
// public int TenantId { get; set; }
|
// public int TenantId { get; set; }
|
||||||
}
|
}
|
||||||
public class CreateQuickUserDto
|
public class MobileUserManageDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid? Id { get; set; }
|
||||||
public string? FirstName { get; set; }
|
public string FirstName { get; set; } = string.Empty;
|
||||||
public string? LastName { get; set; }
|
public string? LastName { get; set; }
|
||||||
|
public string PhoneNumber { get; set; } = string.Empty;
|
||||||
public string? Gender { get; set; }
|
public string? Gender { get; set; }
|
||||||
|
public Guid JobRoleId { get; set; }
|
||||||
public string? CurrentAddress { get; set; }
|
public string? ProfileImage { get; set; }
|
||||||
public string? PhoneNumber { get; set; }
|
|
||||||
|
|
||||||
public string? EmergencyPhoneNumber { get; set; }
|
|
||||||
public string? EmergencyContactPerson { get; set; }
|
|
||||||
|
|
||||||
public Guid? JobRoleId { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
Marco.Pms.Model/Dtos/Mail/MailDetailsDto.cs
Normal file
11
Marco.Pms.Model/Dtos/Mail/MailDetailsDto.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Mail
|
||||||
|
{
|
||||||
|
public class MailDetailsDto
|
||||||
|
{
|
||||||
|
public Guid ProjectId { get; set; }
|
||||||
|
public string Recipient { get; set; } = string.Empty; // Eamil Address of recipient
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
public string Schedule { get; set; } = string.Empty; // json object which includes when to send mail and at what interval
|
||||||
|
public Guid MailListId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Marco.Pms.Model/Dtos/Mail/MailTemeplateDto.cs
Normal file
9
Marco.Pms.Model/Dtos/Mail/MailTemeplateDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Marco.Pms.Model.Dtos.Mail
|
||||||
|
{
|
||||||
|
public class MailTemeplateDto
|
||||||
|
{
|
||||||
|
public string Title { get; set; } = string.Empty;
|
||||||
|
public string Body { get; set; } = string.Empty;
|
||||||
|
public string Keywords { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Marco.Pms.Model/Mail/MailDetails.cs
Normal file
20
Marco.Pms.Model/Mail/MailDetails.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.Mail
|
||||||
|
{
|
||||||
|
public class MailDetails
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid ProjectId { get; set; }
|
||||||
|
public string Recipient { get; set; } = string.Empty; // Eamil Address of recipient
|
||||||
|
public string Subject { get; set; } = string.Empty; // Eamil Address of recipient
|
||||||
|
public string Schedule { get; set; } = string.Empty; // json object which includes when to send mail and at what interval
|
||||||
|
public Guid MailListId { get; set; }
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey(nameof(MailListId))]
|
||||||
|
public MailingList? MailBody { get; set; }
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Marco.Pms.Model/Mail/MailLog.cs
Normal file
13
Marco.Pms.Model/Mail/MailLog.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Marco.Pms.Model.Mail
|
||||||
|
{
|
||||||
|
public class MailLog
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid ProjectId { get; set; }
|
||||||
|
public string Body { get; set; } = string.Empty;
|
||||||
|
public string EmailId { get; set; } = string.Empty;
|
||||||
|
public DateTime TimeStamp { get; set; }
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
public Guid? EmployeeId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Marco.Pms.Model/Mail/MailingList.cs
Normal file
11
Marco.Pms.Model/Mail/MailingList.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.Mail
|
||||||
|
{
|
||||||
|
public class MailingList
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string Title { get; set; } = string.Empty;
|
||||||
|
public string Body { get; set; } = string.Empty;
|
||||||
|
public string Keywords { get; set; } = string.Empty; // Comma seprated list of variables in mail body
|
||||||
|
public Guid TenantId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Dtos.Employees;
|
||||||
|
using Marco.Pms.Model.Employees;
|
||||||
using Marco.Pms.Model.ViewModels.Activities;
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
using Marco.Pms.Model.ViewModels.Employee;
|
using Marco.Pms.Model.ViewModels.Employee;
|
||||||
|
|
||||||
@ -8,6 +9,11 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
{
|
{
|
||||||
public static EmployeeVM ToEmployeeVMFromEmployee(this Employee model)
|
public static EmployeeVM ToEmployeeVMFromEmployee(this Employee model)
|
||||||
{
|
{
|
||||||
|
string? base64String = null;
|
||||||
|
if ((model.Photo != null))
|
||||||
|
{
|
||||||
|
base64String = Convert.ToBase64String(model.Photo);
|
||||||
|
}
|
||||||
return new EmployeeVM
|
return new EmployeeVM
|
||||||
{
|
{
|
||||||
Id = model.Id,
|
Id = model.Id,
|
||||||
@ -27,7 +33,7 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
PanNumber = model.PanNumber,
|
PanNumber = model.PanNumber,
|
||||||
PermanentAddress = model.PermanentAddress,
|
PermanentAddress = model.PermanentAddress,
|
||||||
PhoneNumber = model.PhoneNumber,
|
PhoneNumber = model.PhoneNumber,
|
||||||
Photo = model.Photo,
|
Photo = base64String,
|
||||||
IsActive = model.IsActive,
|
IsActive = model.IsActive,
|
||||||
IsSystem = model.IsSystem,
|
IsSystem = model.IsSystem,
|
||||||
JoiningDate = model.JoiningDate
|
JoiningDate = model.JoiningDate
|
||||||
@ -45,5 +51,30 @@ namespace Marco.Pms.Model.Mapper
|
|||||||
JobRoleName = employee.JobRole != null ? employee.JobRole.Name : ""
|
JobRoleName = employee.JobRole != null ? employee.JobRole.Name : ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
public static Employee ToEmployeeFromMobileUserManageDto(this MobileUserManageDto model, Guid TenantId, byte[]? image)
|
||||||
|
{
|
||||||
|
return new Employee
|
||||||
|
{
|
||||||
|
ApplicationUserId = null,
|
||||||
|
FirstName = model.FirstName,
|
||||||
|
LastName = model.LastName,
|
||||||
|
Email = string.Empty,
|
||||||
|
TenantId = TenantId,
|
||||||
|
CurrentAddress = string.Empty,
|
||||||
|
BirthDate = null,
|
||||||
|
EmergencyPhoneNumber = string.Empty,
|
||||||
|
EmergencyContactPerson = string.Empty,
|
||||||
|
AadharNumber = string.Empty,
|
||||||
|
Gender = model.Gender,
|
||||||
|
MiddleName = string.Empty,
|
||||||
|
PanNumber = string.Empty,
|
||||||
|
PermanentAddress = string.Empty,
|
||||||
|
PhoneNumber = model.PhoneNumber,
|
||||||
|
Photo = image,
|
||||||
|
JobRoleId = model.JobRoleId,
|
||||||
|
JoiningDate = null,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,5 +5,7 @@
|
|||||||
public List<PerformedActivites>? PerformedActivites { get; set; }
|
public List<PerformedActivites>? PerformedActivites { get; set; }
|
||||||
public double TotalPlannedWork { get; set; }
|
public double TotalPlannedWork { get; set; }
|
||||||
public double TotalCompletedWork { get; set; }
|
public double TotalCompletedWork { get; set; }
|
||||||
|
public int ReportPending { get; set; }
|
||||||
|
public int TodaysAssigned { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
public string? FloorName { get; set; }
|
public string? FloorName { get; set; }
|
||||||
public string? WorkAreaName { get; set; }
|
public string? WorkAreaName { get; set; }
|
||||||
public string? ActivityName { get; set; }
|
public string? ActivityName { get; set; }
|
||||||
public string? Comment { get; set; }
|
|
||||||
public double Pending { get; set; }
|
|
||||||
public double AssignedToday { get; set; }
|
public double AssignedToday { get; set; }
|
||||||
public double CompletedToday { get; set; }
|
public double CompletedToday { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
public bool IsActive { get; set; } = true;
|
public bool IsActive { get; set; } = true;
|
||||||
public string? PanNumber { get; set; }
|
public string? PanNumber { get; set; }
|
||||||
|
|
||||||
public byte[]? Photo { get; set; } // To store the captured photo
|
public string? Photo { get; set; } // To store the captured photo
|
||||||
|
|
||||||
public string? ApplicationUserId { get; set; }
|
public string? ApplicationUserId { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -159,7 +159,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(projectDashboardVM, "Success", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(projectDashboardVM, "Success", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet("teams")]
|
[HttpGet("teams")]
|
||||||
public async Task<IActionResult> GetTotalEmployees()
|
public async Task<IActionResult> GetTotalEmployees()
|
||||||
{
|
{
|
||||||
@ -223,7 +222,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return NotFound(ApiResponse<object>.ErrorResponse("No attendance entry was found for this employee", "No attendance entry was found for this employee", 404));
|
return NotFound(ApiResponse<object>.ErrorResponse("No attendance entry was found for this employee", "No attendance entry was found for this employee", 404));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("project-attdendance/{projectId}")]
|
[HttpGet("project-attendance/{projectId}")]
|
||||||
public async Task<IActionResult> GetProjectAttendance(Guid projectId, [FromQuery] string? date)
|
public async Task<IActionResult> GetProjectAttendance(Guid projectId, [FromQuery] string? date)
|
||||||
{
|
{
|
||||||
Guid tenantId = _userHelper.GetTenantId();
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
@ -277,7 +276,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(projectAttendanceVM, $"Attendance record for project {project.Name} for date {currentDate.Date}", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(projectAttendanceVM, $"Attendance record for project {project.Name} for date {currentDate.Date}", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet("activities/{projectId}")]
|
[HttpGet("activities/{projectId}")]
|
||||||
public async Task<IActionResult> GetActivities(Guid projectId, [FromQuery] string? date)
|
public async Task<IActionResult> GetActivities(Guid projectId, [FromQuery] string? date)
|
||||||
{
|
{
|
||||||
@ -285,7 +283,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
DateTime currentDate = DateTime.UtcNow;
|
DateTime currentDate = DateTime.UtcNow;
|
||||||
List<ProjectProgressionVM>? projectProgressionVMs = new List<ProjectProgressionVM>();
|
|
||||||
if (date != null && DateTime.TryParse(date, out currentDate) == false)
|
if (date != null && DateTime.TryParse(date, out currentDate) == false)
|
||||||
{
|
{
|
||||||
_logger.LogError($"user send invalid date");
|
_logger.LogError($"user send invalid date");
|
||||||
@ -333,8 +330,6 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
Building building = buildings.FirstOrDefault(b => b.Id == floor.BuildingId) ?? new Building();
|
Building building = buildings.FirstOrDefault(b => b.Id == floor.BuildingId) ?? new Building();
|
||||||
string buildingName = building.Name ?? "";
|
string buildingName = building.Name ?? "";
|
||||||
|
|
||||||
double pending = workItem.PlannedWork - workItem.CompletedWork;
|
|
||||||
|
|
||||||
PerformedActivites performedTask = new PerformedActivites
|
PerformedActivites performedTask = new PerformedActivites
|
||||||
{
|
{
|
||||||
ActivityName = activityName,
|
ActivityName = activityName,
|
||||||
@ -342,17 +337,19 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
FloorName = floorName,
|
FloorName = floorName,
|
||||||
WorkAreaName = areaName,
|
WorkAreaName = areaName,
|
||||||
AssignedToday = task.PlannedTask,
|
AssignedToday = task.PlannedTask,
|
||||||
Pending = pending,
|
|
||||||
CompletedToday = task.CompletedTask,
|
CompletedToday = task.CompletedTask,
|
||||||
Comment = task.Description
|
|
||||||
};
|
};
|
||||||
performedActivites.Add(performedTask);
|
performedActivites.Add(performedTask);
|
||||||
}
|
}
|
||||||
|
var pendingReport = tasks.Where(t => t.ReportedDate == null).ToList().Count;
|
||||||
|
|
||||||
ActivityReport report = new ActivityReport
|
ActivityReport report = new ActivityReport
|
||||||
{
|
{
|
||||||
PerformedActivites = performedActivites,
|
PerformedActivites = performedActivites,
|
||||||
TotalCompletedWork = totalCompletedTask,
|
TotalCompletedWork = totalCompletedTask,
|
||||||
TotalPlannedWork = totalPlannedTask
|
TotalPlannedWork = totalPlannedTask,
|
||||||
|
ReportPending = pendingReport,
|
||||||
|
TodaysAssigned = tasks.Count
|
||||||
};
|
};
|
||||||
_logger.LogInfo($"Record of performed activities for project {projectId} for date {currentDate.Date} by employee {LoggedInEmployee.Id}");
|
_logger.LogInfo($"Record of performed activities for project {projectId} for date {currentDate.Date} by employee {LoggedInEmployee.Id}");
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(report, $"Record of performed activities for project {project.Name} for date {currentDate.Date}", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(report, $"Record of performed activities for project {project.Name} for date {currentDate.Date}", 200));
|
||||||
|
|||||||
@ -84,8 +84,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("list/{projectid?}")]
|
[Route("list/{projectid?}")]
|
||||||
public async Task<IActionResult> GetEmployeesByProject(Guid? projectid, [FromQuery] bool ShowInactive)
|
public async Task<IActionResult> GetEmployeesByProject(Guid? projectid, [FromQuery] bool ShowInactive)
|
||||||
@ -103,6 +101,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("search/{name}/{projectid?}")]
|
[Route("search/{name}/{projectid?}")]
|
||||||
public async Task<IActionResult> SearchEmployee(string name, Guid? projectid)
|
public async Task<IActionResult> SearchEmployee(string name, Guid? projectid)
|
||||||
@ -264,145 +263,90 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
Employee newEmployee = GetNewEmployeeModel(model, tenantId, string.Empty);
|
Employee newEmployee = GetNewEmployeeModel(model, tenantId, string.Empty);
|
||||||
_context.Employees.Add(newEmployee);
|
_context.Employees.Add(newEmployee);
|
||||||
}
|
}
|
||||||
try
|
await _context.SaveChangesAsync();
|
||||||
{
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return BadRequest(ex.InnerException?.Message ?? ex.Message);
|
|
||||||
}
|
|
||||||
responsemessage = "User created successfully.";
|
responsemessage = "User created successfully.";
|
||||||
|
|
||||||
}
|
}
|
||||||
return Ok(ApiResponse<object>.SuccessResponse("Success.", responsemessage, 200));
|
return Ok(ApiResponse<object>.SuccessResponse("Success.", responsemessage, 200));
|
||||||
}
|
}
|
||||||
//[HttpPost("manage-mobile")]
|
|
||||||
//public async Task<IActionResult> CreateUserMoblie([FromBody] CreateUserDto model)
|
|
||||||
//{
|
|
||||||
// Guid tenantId = _userHelper.GetTenantId();
|
|
||||||
// if (model == null)
|
|
||||||
// return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));
|
|
||||||
|
|
||||||
// if (model.FirstName == null && model.PhoneNumber == null)
|
[HttpPost("manage-mobile")]
|
||||||
// return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));
|
public async Task<IActionResult> CreateUserMoblie([FromBody] MobileUserManageDto model)
|
||||||
|
{
|
||||||
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("User submitted empty or null employee information during employee creation or update in tenant {TenantId}", tenantId);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));
|
||||||
|
}
|
||||||
|
|
||||||
// string responsemessage = "";
|
if (string.IsNullOrWhiteSpace(model.FirstName) || string.IsNullOrWhiteSpace(model.PhoneNumber))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("User submitted empty or null first name or phone number during employee creation or update in tenant {TenantId}", tenantId);
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("First name and phone number are required fields.", "First name and phone number are required fields.", 400));
|
||||||
|
}
|
||||||
|
|
||||||
// if (model.Email != null)
|
if (model.Id == null)
|
||||||
// {
|
{
|
||||||
// // Check if user already exists by email
|
byte[]? imageBytes = null;
|
||||||
// IdentityUser? existingUser = await _userHelper.GetRegisteredUser(model.Email);
|
if (!string.IsNullOrWhiteSpace(model.ProfileImage))
|
||||||
// var existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id && e.IsActive == true);
|
{
|
||||||
// var demo = existingUser != new IdentityUser();
|
try
|
||||||
// if (existingUser != null)
|
{
|
||||||
// {
|
imageBytes = Convert.FromBase64String(model.ProfileImage);
|
||||||
// /* Identity user Exists - Create/update employee Employee */
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid image format.", "Invalid image format", 400));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Employee employee = model.ToEmployeeFromMobileUserManageDto(tenantId, imageBytes);
|
||||||
|
_context.Employees.Add(employee);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
// // Update Employee record
|
EmployeeVM employeeVM = employee.ToEmployeeVMFromEmployee();
|
||||||
// existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Email == model.Email && e.Id == model.Id && e.IsActive == true);
|
|
||||||
// if (existingEmployee != null)
|
|
||||||
// {
|
|
||||||
// existingEmployee = GetUpdateEmployeeModel(model, existingEmployee, existingUser);
|
|
||||||
|
|
||||||
// _context.Employees.Update(existingEmployee);
|
_logger.LogInfo($"Employee {employee.FirstName} {employee.LastName} created in tenant {tenantId}");
|
||||||
// await _context.SaveChangesAsync();
|
return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee created successfully", 200));
|
||||||
// responsemessage = "User updated successfully.";
|
}
|
||||||
// }
|
else
|
||||||
// else
|
{
|
||||||
// {
|
Employee? existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id.Value);
|
||||||
// // Create Employee record if missing
|
if (existingEmployee == null)
|
||||||
// //Employee newEmployee = GetNewEmployeeModel(model, TenantId, existingUser.Id);
|
{
|
||||||
// //_context.Employees.Add(newEmployee);
|
_logger.LogError("User tries to update employee {EmployeeId} but not found in database", model.Id);
|
||||||
// return Conflict(ApiResponse<object>.ErrorResponse("Email already exist", "Email already exist", 409));
|
return NotFound(ApiResponse<object>.ErrorResponse("Employee not found", "Employee not found", 404));
|
||||||
// }
|
}
|
||||||
|
byte[]? imageBytes = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(model.ProfileImage))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
imageBytes = Convert.FromBase64String(model.ProfileImage);
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid image format.", "Invalid image format", 400));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageBytes ??= existingEmployee.Photo;
|
||||||
|
|
||||||
// }
|
existingEmployee.FirstName = model.FirstName;
|
||||||
// else
|
existingEmployee.LastName = model.LastName;
|
||||||
// {
|
existingEmployee.Gender = model.Gender;
|
||||||
// var user = new ApplicationUser
|
existingEmployee.PhoneNumber = model.PhoneNumber;
|
||||||
// {
|
existingEmployee.JobRoleId = model.JobRoleId;
|
||||||
// UserName = model.Email,
|
existingEmployee.Photo = imageBytes;
|
||||||
// Email = model.Email,
|
|
||||||
// EmailConfirmed = true,
|
|
||||||
// TenantId = tenantId
|
|
||||||
|
|
||||||
// };
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
// // Create Identity User
|
EmployeeVM employeeVM = existingEmployee.ToEmployeeVMFromEmployee();
|
||||||
// var result = await _userManager.CreateAsync(user, "User@123");
|
|
||||||
// if (!result.Succeeded)
|
|
||||||
// return Ok(ApiResponse<object>.ErrorResponse("Failed to create user", result.Errors, 400));
|
|
||||||
|
|
||||||
// if (existingEmployee == null)
|
_logger.LogInfo($"Employee {existingEmployee.FirstName} {existingEmployee.LastName} updated in tenant {tenantId}");
|
||||||
// {
|
return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee updated successfully", 200));
|
||||||
// Employee newEmployee = GetNewEmployeeModel(model, tenantId, user.Id);
|
}
|
||||||
// _context.Employees.Add(newEmployee);
|
}
|
||||||
|
|
||||||
// await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
|
||||||
// /* SEND USER REGISTRATION MAIL*/
|
|
||||||
// var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
|
||||||
// var resetLink = $"{_configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
|
|
||||||
// if (newEmployee.FirstName != null)
|
|
||||||
// {
|
|
||||||
// await _emailSender.SendResetPasswordEmailOnRegister(user.Email, newEmployee.FirstName, resetLink);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// existingEmployee.Email = model.Email;
|
|
||||||
// existingEmployee = GetUpdateEmployeeModel(model, existingEmployee, existingUser);
|
|
||||||
|
|
||||||
// _context.Employees.Update(existingEmployee);
|
|
||||||
// await _context.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
|
||||||
// /* SEND USER REGISTRATION MAIL*/
|
|
||||||
// var token = await _userManager.GeneratePasswordResetTokenAsync(user);
|
|
||||||
// var resetLink = $"{_configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
|
|
||||||
// if (existingEmployee.FirstName != null)
|
|
||||||
// {
|
|
||||||
// await _emailSender.SendResetPasswordEmailOnRegister(user.Email, existingEmployee.FirstName, resetLink);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// responsemessage = "User created successfully. Password reset link is sent to registered email";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// var existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id && e.IsActive == true);
|
|
||||||
// if (existingEmployee != null)
|
|
||||||
// {
|
|
||||||
// existingEmployee = GetUpdateEmployeeModel(model, existingEmployee);
|
|
||||||
// _context.Employees.Update(existingEmployee);
|
|
||||||
// responsemessage = "User updated successfully.";
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// // Create Employee record if missing
|
|
||||||
// Employee newEmployee = GetNewEmployeeModel(model, tenantId, string.Empty);
|
|
||||||
// _context.Employees.Add(newEmployee);
|
|
||||||
// }
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// await _context.SaveChangesAsync();
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// return BadRequest(ex.InnerException?.Message ?? ex.Message);
|
|
||||||
// }
|
|
||||||
// responsemessage = "User created successfully.";
|
|
||||||
|
|
||||||
// }
|
|
||||||
// return Ok(ApiResponse<object>.SuccessResponse("Success.", responsemessage, 200));
|
|
||||||
//}
|
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
public async Task<IActionResult> SuspendEmployee(Guid id)
|
public async Task<IActionResult> SuspendEmployee(Guid id)
|
||||||
@ -484,7 +428,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
|
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
|
||||||
{
|
{
|
||||||
var newEmployee = new Employee
|
var newEmployee = new Employee
|
||||||
@ -511,7 +454,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
};
|
};
|
||||||
return newEmployee;
|
return newEmployee;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Employee GetUpdateEmployeeModel(CreateUserDto model, Employee existingEmployee, IdentityUser? existingIdentityUser = null)
|
private static Employee GetUpdateEmployeeModel(CreateUserDto model, Employee existingEmployee, IdentityUser? existingIdentityUser = null)
|
||||||
{
|
{
|
||||||
if (existingEmployee.ApplicationUserId == null && existingIdentityUser != null)
|
if (existingEmployee.ApplicationUserId == null && existingIdentityUser != null)
|
||||||
@ -536,7 +478,6 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
return existingEmployee;
|
return existingEmployee;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<FileDetails> GetFileDetails(IFormFile file)
|
private static async Task<FileDetails> GetFileDetails(IFormFile file)
|
||||||
{
|
{
|
||||||
FileDetails info = new FileDetails();
|
FileDetails info = new FileDetails();
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
using System.Globalization;
|
using System.Data;
|
||||||
|
using System.Globalization;
|
||||||
using Marco.Pms.DataAccess.Data;
|
using Marco.Pms.DataAccess.Data;
|
||||||
using Marco.Pms.Model.Dtos.Attendance;
|
using Marco.Pms.Model.Dtos.Attendance;
|
||||||
using Marco.Pms.Model.Projects;
|
using Marco.Pms.Model.Dtos.Mail;
|
||||||
using Marco.Pms.Model.Roles;
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Mail;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Report;
|
using Marco.Pms.Model.ViewModels.Report;
|
||||||
using MarcoBMS.Services.Helpers;
|
using MarcoBMS.Services.Helpers;
|
||||||
@ -21,198 +23,308 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
{
|
{
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly IEmailSender _emailSender;
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
private readonly ILoggingService _logger;
|
private readonly ILoggingService _logger;
|
||||||
private readonly UserHelper _userHelper;
|
private readonly UserHelper _userHelper;
|
||||||
public ReportController(ApplicationDbContext context, IEmailSender emailSender, IConfiguration configuration, ILoggingService logger, UserHelper userHelper)
|
private readonly IWebHostEnvironment _env;
|
||||||
|
public ReportController(ApplicationDbContext context, IEmailSender emailSender, ILoggingService logger, UserHelper userHelper, IWebHostEnvironment env)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
_configuration = configuration;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_userHelper = userHelper;
|
_userHelper = userHelper;
|
||||||
|
_env = env;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("project-statistics/{id}")]
|
[HttpPost("set-mail")]
|
||||||
public async Task<IActionResult> GetProjectStatistics(Guid id, [FromQuery] string? date)
|
public async Task<IActionResult> AddMailDetails([FromBody] MailDetailsDto mailDetailsDto)
|
||||||
{
|
{
|
||||||
DateTime reportDate = DateTime.UtcNow;
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
if (date != null && DateTime.TryParse(date, out reportDate) == false)
|
MailDetails mailDetails = new MailDetails
|
||||||
{
|
{
|
||||||
_logger.LogError("User sent Invalid from Date while featching project report");
|
ProjectId = mailDetailsDto.ProjectId,
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
|
Recipient = mailDetailsDto.Recipient,
|
||||||
}
|
Schedule = mailDetailsDto.Schedule,
|
||||||
if (id == Guid.Empty)
|
MailListId = mailDetailsDto.MailListId,
|
||||||
|
Subject = mailDetailsDto.Subject,
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
_context.MailDetails.Add(mailDetails);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return Ok("Success");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("mail-template")]
|
||||||
|
public async Task<IActionResult> AddMailTemplate([FromBody] MailTemeplateDto mailTemeplateDto)
|
||||||
|
{
|
||||||
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
|
MailingList mailingList = new MailingList
|
||||||
{
|
{
|
||||||
_logger.LogError("Provided empty project ID while fetching project report");
|
Title = mailTemeplateDto.Title,
|
||||||
return BadRequest(ApiResponse<object>.ErrorResponse("Provided empty ProjectID", "Provided empty ProjectID", 400));
|
Body = mailTemeplateDto.Body,
|
||||||
|
Keywords = mailTemeplateDto.Keywords,
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
_context.MailingList.Add(mailingList);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return Ok("Success");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("project-statistics")]
|
||||||
|
public async Task<IActionResult> SendProjectReport()
|
||||||
|
{
|
||||||
|
Guid tenantId = _userHelper.GetTenantId();
|
||||||
|
|
||||||
|
// Use AsNoTracking() for read-only queries to improve performance
|
||||||
|
List<MailDetails> mailDetails = await _context.MailDetails
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(m => m.MailBody)
|
||||||
|
.Where(m => m.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
int successCount = 0;
|
||||||
|
int notFoundCount = 0;
|
||||||
|
int invalidIdCount = 0;
|
||||||
|
|
||||||
|
var groupedMails = mailDetails
|
||||||
|
.GroupBy(m => new { m.ProjectId, m.MailListId })
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
ProjectId = g.Key.ProjectId,
|
||||||
|
MailListId = g.Key.MailListId,
|
||||||
|
Recipients = g.Select(m => m.Recipient).Distinct().ToList(),
|
||||||
|
MailBody = g.FirstOrDefault()?.MailBody?.Body ?? ""
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var semaphore = new SemaphoreSlim(1);
|
||||||
|
|
||||||
|
// Using Task.WhenAll to send reports concurrently for better performance
|
||||||
|
var sendTasks = groupedMails.Select(async mailDetail =>
|
||||||
|
{
|
||||||
|
await semaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await GetProjectStatistics(mailDetail.ProjectId, mailDetail.Recipients, mailDetail.MailBody, tenantId);
|
||||||
|
if (response.StatusCode == 200)
|
||||||
|
Interlocked.Increment(ref successCount);
|
||||||
|
else if (response.StatusCode == 404)
|
||||||
|
Interlocked.Increment(ref notFoundCount);
|
||||||
|
else if (response.StatusCode == 400)
|
||||||
|
Interlocked.Increment(ref invalidIdCount);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
|
}
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
await Task.WhenAll(sendTasks);
|
||||||
|
//var response = await GetProjectStatistics(Guid.Parse("2618eb89-2823-11f0-9d9e-bc241163f504"), "ashutosh.nehete@marcoaiot.com", tenantId);
|
||||||
|
|
||||||
|
|
||||||
|
_logger.LogInfo(
|
||||||
|
"Emails of project reports sent for tenant {TenantId}. Successfully sent: {SuccessCount}, Projects not found: {NotFoundCount}, Invalid IDs: {InvalidIdsCount}",
|
||||||
|
tenantId, successCount, notFoundCount, invalidIdCount);
|
||||||
|
|
||||||
|
return Ok(ApiResponse<object>.SuccessResponse(
|
||||||
|
new { },
|
||||||
|
$"Reports sent successfully: {successCount}. Projects not found: {notFoundCount}. Invalid IDs: {invalidIdCount}.",
|
||||||
|
200));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves project statistics for a given project ID and sends an email report.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="projectId">The ID of the project.</param>
|
||||||
|
/// <param name="recipientEmail">The email address of the recipient.</param>
|
||||||
|
/// <returns>An ApiResponse indicating the success or failure of retrieving statistics and sending the email.</returns>
|
||||||
|
private async Task<ApiResponse<object>> GetProjectStatistics(Guid projectId, List<string> recipientEmails, string body, Guid tenantId)
|
||||||
|
{
|
||||||
|
DateTime reportDate = DateTime.UtcNow.AddDays(-1).Date;
|
||||||
|
|
||||||
|
if (projectId == Guid.Empty)
|
||||||
|
{
|
||||||
|
_logger.LogError("Provided empty project ID while fetching project report.");
|
||||||
|
return ApiResponse<object>.ErrorResponse("Provided empty Project ID.", "Provided empty Project ID.", 400);
|
||||||
}
|
}
|
||||||
Project? project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == id);
|
|
||||||
|
var project = await _context.Projects
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == projectId);
|
||||||
|
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("User attempted to fetch project progress of project ID {ProjectId} but not found in database", id);
|
_logger.LogWarning("User attempted to fetch project progress for project ID {ProjectId} but not found.", projectId);
|
||||||
return NotFound(ApiResponse<object>.ErrorResponse("Project not found", "Project not found", 404));
|
return ApiResponse<object>.ErrorResponse("Project not found.", "Project not found.", 404);
|
||||||
}
|
}
|
||||||
ProjectStatisticReport statisticReport = new ProjectStatisticReport
|
|
||||||
|
var statisticReport = new ProjectStatisticReport
|
||||||
{
|
{
|
||||||
Date = reportDate,
|
Date = reportDate,
|
||||||
ProjectName = project.Name ?? "",
|
ProjectName = project.Name ?? "",
|
||||||
TimeStamp = DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture)
|
TimeStamp = DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture)
|
||||||
};
|
};
|
||||||
var projectAllocations = await _context.ProjectAllocations.Include(p => p.Employee).Where(p => p.ProjectId == project.Id && p.IsActive).ToListAsync();
|
|
||||||
var assignedEmployeeIds = projectAllocations.Select(p => p.EmployeeId).ToList();
|
|
||||||
var attendances = await _context.Attendes.AsNoTracking().Where(a => a.ProjectID == project.Id && a.InTime != null && a.InTime.Value.Date == reportDate.Date).ToListAsync();
|
|
||||||
var checkedInEmployeeIds = attendances.Select(p => p.EmployeeID).Distinct().ToList();
|
|
||||||
var checkedOutPendingEmployeeIds = attendances.Where(a => a.ProjectID == project.Id && a.InTime != null && a.InTime.Value.Date == reportDate.Date && a.OutTime == null).Select(p => p.EmployeeID).Distinct().ToList();
|
|
||||||
var regularizationEmployeeIds = attendances.Where(a => a.ProjectID == project.Id && a.InTime != null && a.InTime.Value.Date == reportDate.Date && a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE).Select(p => p.EmployeeID).Distinct().ToList();
|
|
||||||
|
|
||||||
|
// Preload relevant data
|
||||||
|
var projectAllocations = await _context.ProjectAllocations
|
||||||
|
.Include(p => p.Employee)
|
||||||
|
.Where(p => p.ProjectId == project.Id && p.IsActive)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var assignedEmployeeIds = projectAllocations.Select(p => p.EmployeeId).ToHashSet();
|
||||||
|
|
||||||
|
var attendances = await _context.Attendes
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(a => a.ProjectID == project.Id && a.InTime != null && a.InTime.Value.Date == reportDate)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var checkedInEmployeeIds = attendances.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
var checkoutPendingIds = attendances.Where(a => a.OutTime == null).Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
var regularizationIds = attendances
|
||||||
|
.Where(a => a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
|
||||||
|
.Select(a => a.EmployeeID).Distinct().ToHashSet();
|
||||||
|
|
||||||
|
// Preload buildings, floors, areas
|
||||||
var buildings = await _context.Buildings.Where(b => b.ProjectId == project.Id).ToListAsync();
|
var buildings = await _context.Buildings.Where(b => b.ProjectId == project.Id).ToListAsync();
|
||||||
var buildingIds = buildings.Select(b => b.Id).Distinct().ToList();
|
var buildingIds = buildings.Select(b => b.Id).ToList();
|
||||||
|
|
||||||
var floors = await _context.Floor.Where(f => buildingIds.Contains(f.BuildingId)).ToListAsync();
|
var floors = await _context.Floor.Where(f => buildingIds.Contains(f.BuildingId)).ToListAsync();
|
||||||
var floorIds = floors.Select(f => f.Id).Distinct().ToList();
|
var floorIds = floors.Select(f => f.Id).ToList();
|
||||||
|
|
||||||
var areas = await _context.WorkAreas.Where(a => floorIds.Contains(a.FloorId)).ToListAsync();
|
var areas = await _context.WorkAreas.Where(a => floorIds.Contains(a.FloorId)).ToListAsync();
|
||||||
var areaIds = areas.Select(a => a.Id).Distinct().ToList();
|
var areaIds = areas.Select(a => a.Id).ToList();
|
||||||
|
|
||||||
var workItems = await _context.WorkItems.Include(i => i.ActivityMaster).Where(i => areaIds.Contains(i.WorkAreaId)).ToListAsync();
|
var workItems = await _context.WorkItems
|
||||||
var itemIds = workItems.Select(i => i.Id).Distinct().ToList();
|
.Include(w => w.ActivityMaster)
|
||||||
|
.Where(w => areaIds.Contains(w.WorkAreaId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
var tasks = await _context.TaskAllocations.Where(t => itemIds.Contains(t.WorkItemId)).ToListAsync();
|
var itemIds = workItems.Select(i => i.Id).ToList();
|
||||||
var taskIds = tasks.Select(t => t.Id).Distinct().ToList();
|
|
||||||
|
|
||||||
var taskMembers = await _context.TaskMembers.Include(m => m.Employee).Where(m => taskIds.Contains(m.TaskAllocationId)).ToListAsync();
|
var tasks = await _context.TaskAllocations
|
||||||
|
.Where(t => itemIds.Contains(t.WorkItemId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
double totalPlannedWork = 0;
|
var taskIds = tasks.Select(t => t.Id).ToList();
|
||||||
double totalCompletedWork = 0;
|
|
||||||
foreach (var items in workItems)
|
|
||||||
{
|
|
||||||
totalPlannedWork += items.PlannedWork;
|
|
||||||
totalCompletedWork += items.CompletedWork;
|
|
||||||
}
|
|
||||||
|
|
||||||
var todayAssigned = tasks.Where(t => t.AssignmentDate.Date == reportDate.Date).ToList();
|
var taskMembers = await _context.TaskMembers
|
||||||
|
.Include(m => m.Employee)
|
||||||
|
.Where(m => taskIds.Contains(m.TaskAllocationId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Aggregate data
|
||||||
|
double totalPlannedWork = workItems.Sum(w => w.PlannedWork);
|
||||||
|
double totalCompletedWork = workItems.Sum(w => w.CompletedWork);
|
||||||
|
|
||||||
|
var todayAssignedTasks = tasks.Where(t => t.AssignmentDate.Date == reportDate).ToList();
|
||||||
var reportPending = tasks.Where(t => t.ReportedDate == null).ToList();
|
var reportPending = tasks.Where(t => t.ReportedDate == null).ToList();
|
||||||
|
|
||||||
double totalPlannedTask = 0;
|
double totalPlannedTask = todayAssignedTasks.Sum(t => t.PlannedTask);
|
||||||
double totalCompletedTask = 0;
|
double totalCompletedTask = todayAssignedTasks.Sum(t => t.CompletedTask);
|
||||||
foreach (var items in todayAssigned)
|
|
||||||
{
|
|
||||||
totalPlannedTask += items.PlannedTask;
|
|
||||||
totalCompletedTask += items.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var jobRoles = await _context.JobRoles.Where(r => r.TenantId == project.TenantId).ToListAsync();
|
var jobRoles = await _context.JobRoles
|
||||||
List<TeamOnSite> teamOnSite = new List<TeamOnSite>();
|
.Where(j => j.TenantId == project.TenantId)
|
||||||
foreach (var role in jobRoles)
|
.ToListAsync();
|
||||||
{
|
|
||||||
int numberOfEmployees = 0;
|
// Team on site
|
||||||
var roleassigned = projectAllocations.Where(p => p.JobRoleId == role.Id && checkedInEmployeeIds.Contains(p.EmployeeId)).ToList();
|
var teamOnSite = jobRoles
|
||||||
if (roleassigned.Count > 0)
|
.Select(role =>
|
||||||
{
|
{
|
||||||
numberOfEmployees = roleassigned.Count;
|
var count = projectAllocations.Count(p => p.JobRoleId == role.Id && checkedInEmployeeIds.Contains(p.EmployeeId));
|
||||||
}
|
return new TeamOnSite { RoleName = role.Name, NumberofEmployees = count };
|
||||||
TeamOnSite team = new TeamOnSite
|
})
|
||||||
{
|
.OrderByDescending(t => t.NumberofEmployees)
|
||||||
RoleName = role.Name,
|
.ToList();
|
||||||
NumberofEmployees = numberOfEmployees,
|
|
||||||
};
|
// Task details
|
||||||
teamOnSite.Add(team);
|
var performedTasks = todayAssignedTasks.Select(task =>
|
||||||
}
|
|
||||||
List<PerformedTask> performedTasks = new List<PerformedTask>();
|
|
||||||
var todaysTask = tasks.Where(t => t.AssignmentDate.Date == reportDate.Date).ToList();
|
|
||||||
foreach (var task in todaysTask)
|
|
||||||
{
|
{
|
||||||
WorkItem workItem = workItems.FirstOrDefault(i => i.Id == task.WorkItemId) ?? new WorkItem();
|
var workItem = workItems.FirstOrDefault(w => w.Id == task.WorkItemId);
|
||||||
string activityName = (workItem.ActivityMaster != null ? workItem.ActivityMaster.ActivityName : "") ?? "";
|
var area = areas.FirstOrDefault(a => a.Id == workItem?.WorkAreaId);
|
||||||
|
var floor = floors.FirstOrDefault(f => f.Id == area?.FloorId);
|
||||||
|
var building = buildings.FirstOrDefault(b => b.Id == floor?.BuildingId);
|
||||||
|
|
||||||
WorkArea workArea = areas.FirstOrDefault(a => a.Id == workItem.WorkAreaId) ?? new WorkArea();
|
string activityName = workItem?.ActivityMaster?.ActivityName ?? "";
|
||||||
string areaName = workArea.AreaName ?? "";
|
string location = $"{building?.Name} > {floor?.FloorName}</span><br/><span style=\"color: gray; font-size: small; padding-left: 10px;\"> {floor?.FloorName}-{area?.AreaName}";
|
||||||
|
double pending = (workItem?.PlannedWork ?? 0) - (workItem?.CompletedWork ?? 0);
|
||||||
|
|
||||||
Floor floor = floors.FirstOrDefault(f => f.Id == workArea.FloorId) ?? new Floor();
|
var taskTeam = taskMembers
|
||||||
string floorName = floor.FloorName ?? "";
|
.Where(m => m.TaskAllocationId == task.Id)
|
||||||
|
.Select(m =>
|
||||||
|
{
|
||||||
|
string name = $"{m.Employee?.FirstName ?? ""} {m.Employee?.LastName ?? ""}";
|
||||||
|
var role = jobRoles.FirstOrDefault(r => r.Id == m.Employee?.JobRoleId);
|
||||||
|
return new TaskTeam { Name = name, RoleName = role?.Name ?? "" };
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
Building building = buildings.FirstOrDefault(b => b.Id == floor.BuildingId) ?? new Building();
|
return new PerformedTask
|
||||||
string buildingName = building.Name ?? "";
|
|
||||||
|
|
||||||
string location = $"{buildingName} > {floorName} </span><br/><span style=\"color: gray; font-size: small; padding-left: 10px;\"> {floorName}-{areaName}";
|
|
||||||
double pending = workItem.PlannedWork - workItem.CompletedWork;
|
|
||||||
PerformedTask performedTask = new PerformedTask
|
|
||||||
{
|
{
|
||||||
Activity = activityName,
|
Activity = activityName,
|
||||||
Location = location,
|
Location = location,
|
||||||
AssignedToday = task.PlannedTask,
|
AssignedToday = task.PlannedTask,
|
||||||
Pending = pending,
|
|
||||||
CompletedToday = task.CompletedTask,
|
CompletedToday = task.CompletedTask,
|
||||||
Comment = task.Description
|
Pending = pending,
|
||||||
|
Comment = task.Description,
|
||||||
|
Team = taskTeam
|
||||||
};
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
var taskTeams = taskMembers.Where(m => m.TaskAllocationId == task.Id).ToList();
|
// Attendance details
|
||||||
List<TaskTeam> Team = new List<TaskTeam>();
|
var performedAttendance = attendances.Select(att =>
|
||||||
foreach (var team in taskTeams)
|
|
||||||
{
|
|
||||||
string firstName = (team.Employee != null ? team.Employee.FirstName : "") ?? "";
|
|
||||||
string lastName = (team.Employee != null ? team.Employee.LastName : "") ?? "";
|
|
||||||
string name = $"{firstName} {lastName}";
|
|
||||||
|
|
||||||
JobRole role = jobRoles.FirstOrDefault(r => r.Id == (team.Employee != null ? team.Employee.JobRoleId : Guid.Empty)) ?? new JobRole();
|
|
||||||
string roleName = role.Name ?? "";
|
|
||||||
|
|
||||||
TaskTeam taskTeam = new TaskTeam
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
RoleName = roleName,
|
|
||||||
};
|
|
||||||
Team.Add(taskTeam);
|
|
||||||
}
|
|
||||||
performedTask.Team = Team;
|
|
||||||
performedTasks.Add(performedTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PerformedAttendance> performedAttendances = new List<PerformedAttendance>();
|
|
||||||
foreach (var attendance in attendances)
|
|
||||||
{
|
{
|
||||||
ProjectAllocation projectAllocation = projectAllocations.FirstOrDefault(p => p.EmployeeId == attendance.EmployeeID) ?? new ProjectAllocation();
|
var alloc = projectAllocations.FirstOrDefault(p => p.EmployeeId == att.EmployeeID);
|
||||||
JobRole role = jobRoles.FirstOrDefault(r => r.Id == projectAllocation.JobRoleId) ?? new JobRole();
|
var role = jobRoles.FirstOrDefault(r => r.Id == alloc?.JobRoleId);
|
||||||
|
string name = $"{alloc?.Employee?.FirstName ?? ""} {alloc?.Employee?.LastName ?? ""}";
|
||||||
|
|
||||||
string firstName = (projectAllocation.Employee != null ? projectAllocation.Employee.FirstName : "") ?? "";
|
return new PerformedAttendance
|
||||||
string lastName = (projectAllocation.Employee != null ? projectAllocation.Employee.LastName : "") ?? "";
|
|
||||||
string name = $"{firstName} {lastName}";
|
|
||||||
PerformedAttendance performedAttendance = new PerformedAttendance
|
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
RoleName = role.Name ?? "",
|
RoleName = role?.Name ?? "",
|
||||||
InTime = attendance.InTime ?? DateTime.UtcNow,
|
InTime = att.InTime ?? DateTime.UtcNow,
|
||||||
OutTime = attendance.OutTime,
|
OutTime = att.OutTime,
|
||||||
Comment = attendance.Comment
|
Comment = att.Comment
|
||||||
};
|
};
|
||||||
performedAttendances.Add(performedAttendance);
|
}).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
|
// Fill report
|
||||||
statisticReport.TodaysAttendances = checkedInEmployeeIds.Count;
|
statisticReport.TodaysAttendances = checkedInEmployeeIds.Count;
|
||||||
statisticReport.TotalEmployees = assignedEmployeeIds.Count;
|
statisticReport.TotalEmployees = assignedEmployeeIds.Count;
|
||||||
statisticReport.RegularizationPending = regularizationEmployeeIds.Count;
|
statisticReport.RegularizationPending = regularizationIds.Count;
|
||||||
statisticReport.CheckoutPending = checkedOutPendingEmployeeIds.Count;
|
statisticReport.CheckoutPending = checkoutPendingIds.Count;
|
||||||
statisticReport.TotalPlannedWork = totalPlannedWork;
|
statisticReport.TotalPlannedWork = totalPlannedWork;
|
||||||
statisticReport.TotalCompletedWork = totalCompletedWork;
|
statisticReport.TotalCompletedWork = totalCompletedWork;
|
||||||
statisticReport.TotalPlannedTask = totalPlannedTask;
|
statisticReport.TotalPlannedTask = totalPlannedTask;
|
||||||
statisticReport.TotalCompletedTask = totalCompletedTask;
|
statisticReport.TotalCompletedTask = totalCompletedTask;
|
||||||
statisticReport.CompletionStatus = totalCompletedWork / totalPlannedWork;
|
statisticReport.CompletionStatus = totalPlannedWork > 0 ? totalCompletedWork / totalPlannedWork : 0;
|
||||||
statisticReport.TodaysAssignTasks = todayAssigned.Count;
|
statisticReport.TodaysAssignTasks = todayAssignedTasks.Count;
|
||||||
statisticReport.ReportPending = reportPending.Count;
|
statisticReport.ReportPending = reportPending.Count;
|
||||||
statisticReport.TeamOnSite = teamOnSite.OrderByDescending(c => c.NumberofEmployees).ToList();
|
statisticReport.TeamOnSite = teamOnSite;
|
||||||
statisticReport.PerformedTasks = performedTasks;
|
statisticReport.PerformedTasks = performedTasks;
|
||||||
statisticReport.PerformedAttendance = performedAttendances;
|
statisticReport.PerformedAttendance = performedAttendance;
|
||||||
|
|
||||||
string emails = _configuration["MailingList:ProjectStatisticsReceivers"] ?? "";
|
// Send Email
|
||||||
List<string> result = emails
|
var emailBody = await _emailSender.SendProjectStatisticsEmail(recipientEmails, body, statisticReport);
|
||||||
.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
var employee = await _context.Employees.FirstOrDefaultAsync(e => e.Email != null && recipientEmails.Contains(e.Email)) ?? new Employee();
|
||||||
.Select(item => item.Trim())
|
|
||||||
.ToList();
|
List<MailLog> mailLogs = new List<MailLog>();
|
||||||
await _emailSender.SendProjectStatisticsEmail(result, statisticReport);
|
foreach (var recipientEmail in recipientEmails)
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Email sent successfully", 200));
|
{
|
||||||
|
mailLogs.Add(
|
||||||
|
new MailLog
|
||||||
|
{
|
||||||
|
ProjectId = projectId,
|
||||||
|
EmailId = recipientEmail,
|
||||||
|
Body = emailBody,
|
||||||
|
EmployeeId = employee.Id,
|
||||||
|
TimeStamp = DateTime.UtcNow,
|
||||||
|
TenantId = tenantId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.MailLogs.AddRange(mailLogs);
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return ApiResponse<object>.SuccessResponse(statisticReport, "Email sent successfully", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -442,7 +442,7 @@
|
|||||||
Regularization Pending
|
Regularization Pending
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 25px; color: #bc3803; margin: 20px 20px 0px !important; font-weight: bold;">
|
<div style="font-size: 25px; color: #bc3803; margin: 20px 20px 0px !important; font-weight: bold;">
|
||||||
{{REGULRIZATION_PENDING}}
|
{{REGULARIZATION_PENDING}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -453,7 +453,7 @@
|
|||||||
Checkout Pending
|
Checkout Pending
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 25px; color: #bc3803; margin: 20px 20px 0px !important; font-weight: bold;">
|
<div style="font-size: 25px; color: #bc3803; margin: 20px 20px 0px !important; font-weight: bold;">
|
||||||
{{CHECKOUT_PRNDING}}
|
{{CHECKOUT_PENDING}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -112,90 +112,127 @@ namespace MarcoBMS.Services.Service
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendProjectStatisticsEmail(List<string> toEmails, ProjectStatisticReport report)
|
public async Task<string> SendProjectStatisticsEmail(List<string> toEmails, string emailBody, ProjectStatisticReport report)
|
||||||
{
|
{
|
||||||
//List<string> toEmails = [
|
|
||||||
// "ashutosh.nehete@marcoaiot.com"
|
|
||||||
//];
|
|
||||||
var date = report.Date.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture);
|
var date = report.Date.ToString("dd-MMM-yyyy", CultureInfo.InvariantCulture);
|
||||||
var replacements = new Dictionary<string, string>
|
var replacements = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{"DATE",date },
|
{"DATE", date},
|
||||||
{"PROJECT_NAME",report.ProjectName },
|
{"PROJECT_NAME", report.ProjectName},
|
||||||
{"TIMESTAMP",report.TimeStamp },
|
{"TIMESTAMP", report.TimeStamp},
|
||||||
{"TODAYS_ATTENDANCES", report.TodaysAttendances.ToString("N0")},
|
{"TODAYS_ATTENDANCES", report.TodaysAttendances.ToString("N0")},
|
||||||
{"TOTAL_EMPLOYEES",report.TotalEmployees.ToString("N0") },
|
{"TOTAL_EMPLOYEES", report.TotalEmployees.ToString("N0")},
|
||||||
{"TODAYS_PLANNED",report.TotalPlannedTask.ToString("N0") },
|
{"TODAYS_PLANNED", report.TotalPlannedTask.ToString("N0")},
|
||||||
{"TODAYS_COMPLETED",report.TotalCompletedTask.ToString("N0") },
|
{"TODAYS_COMPLETED", report.TotalCompletedTask.ToString("N0")},
|
||||||
{"REGULRIZATION_PENDING", report.RegularizationPending.ToString("N0") },
|
{"REGULARIZATION_PENDING", report.RegularizationPending.ToString("N0")},
|
||||||
{"CHECKOUT_PRNDING",report.CheckoutPending.ToString("N0") },
|
{"CHECKOUT_PENDING", report.CheckoutPending.ToString("N0")},
|
||||||
{"TOTAL_PLANNED",report.TotalPlannedWork.ToString("N0") },
|
{"TOTAL_PLANNED", report.TotalPlannedWork.ToString("N0")},
|
||||||
{"TOTAL_COMPLETED",report.TotalCompletedWork.ToString() },
|
{"TOTAL_COMPLETED", report.TotalCompletedWork.ToString("N0")},
|
||||||
{"PROJECT_STATUS",report.CompletionStatus.ToString("P") },
|
{"PROJECT_STATUS", report.CompletionStatus.ToString("P")},
|
||||||
{"TODAYS_ASSIGNED",report.TodaysAssignTasks.ToString("N0") },
|
{"TODAYS_ASSIGNED", report.TodaysAssignTasks.ToString("N0")},
|
||||||
{"REPORT_PENDING",report.ReportPending.ToString("N0") }
|
{"REPORT_PENDING", report.ReportPending.ToString("N0")}
|
||||||
};
|
};
|
||||||
|
|
||||||
string emailBody = await GetEmailTemplate("project-report", replacements);
|
foreach (var item in replacements)
|
||||||
//string emailBody = await GetEmailTemplate("test-project", replacements);
|
|
||||||
|
|
||||||
var teamHtml = new StringBuilder();
|
|
||||||
teamHtml.Append("<tr style=\"vertical-align:middle\">");
|
|
||||||
int flag = 0;
|
|
||||||
foreach (var item in report.TeamOnSite)
|
|
||||||
{
|
{
|
||||||
if (flag == 6)
|
emailBody = emailBody.Replace($"{{{{{item.Key}}}}}", item.Value);
|
||||||
{
|
|
||||||
teamHtml.Append("</tr>");
|
|
||||||
teamHtml.Append("<tr style=\"vertical-align:middle\">");
|
|
||||||
flag = 0;
|
|
||||||
}
|
|
||||||
teamHtml.AppendFormat("<td class=\"team\" style=\"text-align:center\"><div style=\"border: 1px solid #d5d5d5; border-radius: 10px; margin: 10px 10px; padding: 10px;\"><div style=\"font-size: 15px; color: #525b75 \">{0}</div> <div style=\"font-size: 20px; color: #003cc7; margin: 20px !important; font-weight: bold; \">{1}</div></div></td>", item.RoleName, item.NumberofEmployees);
|
|
||||||
flag += 1;
|
|
||||||
}
|
|
||||||
teamHtml.Append("</tr>");
|
|
||||||
emailBody = emailBody.Replace("{{TEAM_ON_SITE}}", teamHtml.ToString());
|
|
||||||
|
|
||||||
var taskHtml = new StringBuilder();
|
|
||||||
if (report.PerformedTasks.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var task in report.PerformedTasks)
|
|
||||||
{
|
|
||||||
taskHtml.AppendFormat("<tr>\r\n<td style=\"text-align:left;\">\r\n<span style=\"padding-left: 10px; text-align: left;\">\r\n {0} \r\n</span><br />\r\n<span style=\"color: gray; font-size: small; padding-left: 10px;\"> {1} </span>\r\n</td>\r\n<td style=\"text-align:center\">\r\n {2} / {3} \r\n</td>\r\n<td style=\"text-align:center\">\r\n {4} \r\n</td>\r\n<td style=\"text-align:center\"> {5} </td>\r\n <td style=\"padding-left: 10px; text-align: left;\">\r\n",
|
|
||||||
task.Activity, task.Location, task.AssignedToday, task.Pending, task.CompletedToday, report.Date.ToString("dd-MMM-yyy"));
|
|
||||||
foreach (var member in task.Team)
|
|
||||||
{
|
|
||||||
taskHtml.AppendFormat(" {0} \r\n<span style=\"color: gray; font-size: small; padding-left: 10px;\">({1})</span>\r\n<br />",
|
|
||||||
member.Name, member.RoleName);
|
|
||||||
}
|
|
||||||
taskHtml.AppendFormat("</td>\r\n<td style=\"padding-left: 10px; max-width: 150px; text-align: left;\"> {0} </td>\r\n</tr>", task.Comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
taskHtml.Append("<tr><td style=\"padding: 10px 0px 5px;\" colspan=\"6\"><span style=\"line-height: 25.2px; color: #666666;margin:10px\">No Activities (Tasks) Performed Today</span></td></tr>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emailBody = emailBody.Replace("{{PERFORMED_TASK}}", taskHtml.ToString());
|
emailBody = emailBody.Replace("{{TEAM_ON_SITE}}", BuildTeamOnSiteHtml(report.TeamOnSite));
|
||||||
|
emailBody = emailBody.Replace("{{PERFORMED_TASK}}", BuildPerformedTaskHtml(report.PerformedTasks, report.Date));
|
||||||
|
emailBody = emailBody.Replace("{{PERFORMED_ATTENDANCE}}", BuildPerformedAttendanceHtml(report.PerformedAttendance));
|
||||||
|
|
||||||
var attendanceHtml = new StringBuilder();
|
|
||||||
if (report.PerformedAttendance.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var attendance in report.PerformedAttendance)
|
|
||||||
{
|
|
||||||
attendanceHtml.AppendFormat("<tr>\r\n<td style=\"text-align:left\">\r\n<span style=\"padding-left:10px;\"> {0} </span>\r\n</td>\r\n<td style=\"text-align:center\"> {1} </td>\r\n<td style=\"text-align:center\"> {2} </td>\r\n<td style=\"text-align:center\"> {3} </td>\r\n<td style=\"padding-left:10px; max-width:150px\"> {4} </td>\r\n</tr>",
|
|
||||||
attendance.Name, attendance.RoleName, attendance.InTime.ToString("dd-MMM-yyyy h:mm tt", CultureInfo.InvariantCulture), (attendance.OutTime != null ? attendance.OutTime.Value.ToString("dd-MMM-yyyy h:mm tt", CultureInfo.InvariantCulture) : ""), attendance.Comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attendanceHtml.Append("<tr><td style=\"padding: 10px 0px 5px;\" colspan=\"5\"><span style=\"line-height: 25.2px; color: #666666;margin:10px\">No Attendance Performed Today</span></td></tr>");
|
|
||||||
}
|
|
||||||
|
|
||||||
emailBody = emailBody.Replace("{{PERFORMED_ATTENDANCE}}", attendanceHtml.ToString());
|
|
||||||
string subject = $"DPR - {date} - {report.ProjectName}";
|
string subject = $"DPR - {date} - {report.ProjectName}";
|
||||||
await SendEmailAsync(toEmails, subject, emailBody);
|
await SendEmailAsync(toEmails, subject, emailBody);
|
||||||
|
return emailBody;
|
||||||
|
}
|
||||||
|
private string BuildTeamOnSiteHtml(List<TeamOnSite> team)
|
||||||
|
{
|
||||||
|
if (team == null || !team.Any()) return "";
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("<tr style=\"vertical-align:middle\">");
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
foreach (var member in team)
|
||||||
|
{
|
||||||
|
if (count == 6)
|
||||||
|
{
|
||||||
|
sb.Append("</tr><tr style=\"vertical-align:middle\">");
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendFormat(
|
||||||
|
"<td class=\"team\" style=\"text-align:center\">" +
|
||||||
|
"<div style=\"border: 1px solid #d5d5d5; border-radius: 10px; margin: 10px; padding: 10px;\">" +
|
||||||
|
"<div style=\"font-size: 15px; color: #525b75\">{0}</div>" +
|
||||||
|
"<div style=\"font-size: 20px; color: #003cc7; margin: 20px !important; font-weight: bold;\">{1}</div>" +
|
||||||
|
"</div></td>", member.RoleName, member.NumberofEmployees);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("</tr>");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
private string BuildPerformedTaskHtml(List<PerformedTask> tasks, DateTime reportDate)
|
||||||
|
{
|
||||||
|
if (tasks == null || !tasks.Any())
|
||||||
|
{
|
||||||
|
return "<tr><td style=\"padding: 10px 0px 5px;\" colspan=\"6\">" +
|
||||||
|
"<span style=\"line-height: 25.2px; color: #666666;margin:10px\">" +
|
||||||
|
"No Activities (Tasks) Performed Today</span></td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("<tr>" +
|
||||||
|
"<td style=\"text-align:left;\"><span style=\"padding-left: 10px;\">{0}</span><br />" +
|
||||||
|
"<span style=\"color: gray; font-size: small; padding-left: 10px;\">{1}</span></td>" +
|
||||||
|
"<td style=\"text-align:center\">{2} / {3}</td>" +
|
||||||
|
"<td style=\"text-align:center\">{4}</td>" +
|
||||||
|
"<td style=\"text-align:center\">{5}</td>" +
|
||||||
|
"<td style=\"padding-left: 10px; text-align: left;\">",
|
||||||
|
task.Activity, task.Location, task.AssignedToday, task.Pending, task.CompletedToday, reportDate.ToString("dd-MMM-yyyy"));
|
||||||
|
|
||||||
|
foreach (var member in task.Team)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("{0} <span style=\"color: gray; font-size: small; padding-left: 10px;\">({1})</span><br />",
|
||||||
|
member.Name, member.RoleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendFormat("</td><td style=\"padding-left: 10px; max-width: 150px; text-align: left;\">{0}</td></tr>", task.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
private string BuildPerformedAttendanceHtml(List<PerformedAttendance> attendances)
|
||||||
|
{
|
||||||
|
if (attendances == null || !attendances.Any())
|
||||||
|
{
|
||||||
|
return "<tr><td style=\"padding: 10px 0px 5px;\" colspan=\"5\">" +
|
||||||
|
"<span style=\"line-height: 25.2px; color: #666666;margin:10px\">No Attendance Performed Today</span></td></tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var a in attendances)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("<tr>" +
|
||||||
|
"<td style=\"text-align:left\"><span style=\"padding-left:10px;\">{0}</span></td>" +
|
||||||
|
"<td style=\"text-align:center\">{1}</td>" +
|
||||||
|
"<td style=\"text-align:center\">{2}</td>" +
|
||||||
|
"<td style=\"text-align:center\">{3}</td>" +
|
||||||
|
"<td style=\"padding-left:10px; max-width:150px\">{4}</td>" +
|
||||||
|
"</tr>",
|
||||||
|
a.Name,
|
||||||
|
a.RoleName,
|
||||||
|
a.InTime.ToString("dd-MMM-yyyy h:mm tt", CultureInfo.InvariantCulture),
|
||||||
|
a.OutTime?.ToString("dd-MMM-yyyy h:mm tt", CultureInfo.InvariantCulture) ?? "",
|
||||||
|
a.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendEmailAsync(List<string> toEmails, string subject, string body)
|
public async Task SendEmailAsync(List<string> toEmails, string subject, string body)
|
||||||
|
|||||||
@ -10,6 +10,6 @@ namespace MarcoBMS.Services.Service
|
|||||||
Task SendResetPasswordSuccessEmail(string toEmail, string userName);
|
Task SendResetPasswordSuccessEmail(string toEmail, string userName);
|
||||||
Task SendRequestDemoEmail(List<string> toEmails, InquiryEmailObject demoEmailObject);
|
Task SendRequestDemoEmail(List<string> toEmails, InquiryEmailObject demoEmailObject);
|
||||||
Task SendEmailAsync(List<string> toEmails, string subject, string body);
|
Task SendEmailAsync(List<string> toEmails, string subject, string body);
|
||||||
Task SendProjectStatisticsEmail(List<string> toEmails, ProjectStatisticReport report);
|
Task<string> SendProjectStatisticsEmail(List<string> toEmails, string emailBody, ProjectStatisticReport report);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
//"DefaultConnectionString": "Server=localhost;port=3306;User ID=root;Password=root;Database=MarcoBMS2"
|
|
||||||
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMSGuid"
|
"DefaultConnectionString": "Server=147.93.98.152;User ID=devuser;Password=AppUser@123$;Database=MarcoBMSGuid"
|
||||||
},
|
},
|
||||||
"SmtpSettings": {
|
"SmtpSettings": {
|
||||||
@ -36,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
"MailingList": {
|
"MailingList": {
|
||||||
"RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com",
|
"RequestDemoReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com",
|
||||||
"ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
//"ProjectStatisticsReceivers": "ashutosh.nehete@marcoaiot.com;vikas@marcoaiot.com;umesh@marcoait.com"
|
||||||
},
|
},
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"AccessKey": "AKIARZDBH3VDMSUUY2FX",
|
"AccessKey": "AKIARZDBH3VDMSUUY2FX",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user