Skip to content

Commit 3e0f98e

Browse files
feat: Enhance AvoirFournisseur and FactureAvoirFournisseur features with printing capabilities
- Added functionality to print AvoirFournisseur and FactureAvoirFournisseur documents from various components, improving user experience and accessibility. - Implemented automatic number generation for facture avoir when not provided, ensuring valid display numbers. - Enhanced logging for generated numbers and printing processes to facilitate better traceability and error handling. - Updated UI components to include print buttons and improved layout for better interaction.
1 parent d07889f commit 3e0f98e

File tree

13 files changed

+1042
-4
lines changed

13 files changed

+1042
-4
lines changed

src/TunNetCom.SilkRoadErp.Sales.Api/Features/FactureAvoirFournisseur/CreateFactureAvoirFournisseur/CreateFactureAvoirFournisseurCommandHandler.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,18 @@ public async Task<Result<int>> Handle(CreateFactureAvoirFournisseurCommand comma
6464
return Result.Fail("no_active_accounting_year");
6565
}
6666

67+
// Generate number when not provided (0) so the facture avoir always has a valid display number
68+
var numFactureAvoirFourSurPage = command.NumFactureAvoirFourSurPage;
69+
if (numFactureAvoirFourSurPage <= 0)
70+
{
71+
numFactureAvoirFourSurPage = await _numberGeneratorService.GenerateFactureAvoirFournisseurNumberAsync(
72+
activeAccountingYear.Id,
73+
cancellationToken);
74+
_logger.LogInformation("Generated NumFactureAvoirFourSurPage: {Num}", numFactureAvoirFourSurPage);
75+
}
76+
6777
var factureAvoirFournisseur = Domain.Entites.FactureAvoirFournisseur.CreateFactureAvoirFournisseur(
68-
command.NumFactureAvoirFourSurPage, // NumFactureAvoirFourSurPage
78+
numFactureAvoirFourSurPage,
6979
command.IdFournisseur,
7080
command.Date,
7181
command.FactureFournisseurId,

src/TunNetCom.SilkRoadErp.Sales.Api/Features/FactureAvoirFournisseur/GetFactureAvoirFournisseurWithSummaries/GetFactureAvoirFournisseurWithSummariesQueryHandler.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
using TunNetCom.SilkRoadErp.Sales.Api.Infrastructure.Services;
12
using TunNetCom.SilkRoadErp.Sales.Contracts.FactureAvoirFournisseur;
23

34
namespace TunNetCom.SilkRoadErp.Sales.Api.Features.FactureAvoirFournisseur.GetFactureAvoirFournisseurWithSummaries;
45

56
public class GetFactureAvoirFournisseurWithSummariesQueryHandler(
67
SalesContext _context,
7-
ILogger<GetFactureAvoirFournisseurWithSummariesQueryHandler> _logger)
8+
ILogger<GetFactureAvoirFournisseurWithSummariesQueryHandler> _logger,
9+
INumberGeneratorService _numberGeneratorService)
810
: IRequestHandler<GetFactureAvoirFournisseurWithSummariesQuery, GetFactureAvoirFournisseurWithSummariesResponse>
911
{
1012
private const string _idColumnName = nameof(FactureAvoirFournisseurBaseInfo.Id);
@@ -128,6 +130,17 @@ from l in a.LigneAvoirFournisseur
128130
.Take(request.PageSize)
129131
.ToListAsync(cancellationToken);
130132

133+
// Backfill NumFactureAvoirFourSurPage when it is 0 (existing records created before auto-generation)
134+
foreach (var x in factureAvoirData.Where(x => x.f.NumFactureAvoirFourSurPage <= 0))
135+
{
136+
var generatedNum = await _numberGeneratorService.GenerateFactureAvoirFournisseurNumberAsync(
137+
x.f.AccountingYearId,
138+
cancellationToken);
139+
x.f.NumFactureAvoirFourSurPage = generatedNum;
140+
_logger.LogInformation("Backfilled NumFactureAvoirFourSurPage for FactureAvoirFournisseur Id={Id} with {Num}", x.f.Id, generatedNum);
141+
await _context.SaveChangesAsync(cancellationToken);
142+
}
143+
131144
// Map to DTO in memory to avoid SQL conversion issues with Statut enum (like InvoiceBaseInfosController)
132145
var items = factureAvoirData
133146
.Select(x => new FactureAvoirFournisseurBaseInfo

src/WebApps/TunNetCom.SilkRoadErp.Sales.WebApp/Components/Pages/AvoirFournisseur/AddOrUpdateAvoirFournisseur.razor

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
@using TunNetCom.SilkRoadErp.Sales.WebApp.Components.Pages.AvoirFournisseur
1919
@using TunNetCom.SilkRoadErp.Sales.Contracts.Providers
2020
@using TunNetCom.SilkRoadErp.Sales.Contracts.Common
21+
@using TunNetCom.SilkRoadErp.Sales.Domain.Entites
22+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Reports.AvoirFournisseur
23+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Infrastructure
2124

2225
@inject IStringLocalizer<SharedResource> Localizer
2326
@inject Radzen.NotificationService NotificationService
@@ -29,6 +32,8 @@
2932
@inject ILogger<AddOrUpdateAvoirFournisseur> logger
3033
@inject DialogService DialogService
3134
@inject NavigationManager NavigationManager
35+
@inject PrintAvoirFournisseurService PrintAvoirFournisseurService
36+
@inject IPrintService PrintServiceInfra
3237

3338
<style>
3439
.header-actions {
@@ -142,6 +147,16 @@ else
142147
<RadzenDropDownDataGridColumn Property="@nameof(ProviderResponse.Nom)" Title="@Localizer["name"]" Width="220px" />
143148
</Columns>
144149
</RadzenDropDownDataGrid>
150+
@if (IsAvoirFournisseurSaved)
151+
{
152+
<RadzenButton Icon="print"
153+
Text="Imprimer"
154+
ButtonStyle="ButtonStyle.Light"
155+
Size="ButtonSize.Medium"
156+
Click="@OnPrintAvoirFournisseur"
157+
Title="Imprimer l'avoir fournisseur"
158+
Style="margin-left: 8px;" />
159+
}
145160
</div>
146161
</div>
147162

@@ -192,6 +207,8 @@ else
192207
private GetAppParametersResponse getAppParametersResponse;
193208
private int? selectedFournisseurId;
194209

210+
private bool IsAvoirFournisseurSaved => !string.IsNullOrEmpty(id) && int.TryParse(id, out var parsedId) && parsedId > 0;
211+
195212
protected override async Task OnInitializedAsync()
196213
{
197214
await base.OnInitializedAsync();
@@ -336,6 +353,58 @@ else
336353
}
337354
}
338355

356+
private async Task OnPrintAvoirFournisseur()
357+
{
358+
if (!int.TryParse(id, out var avoirId) || avoirId <= 0) return;
359+
await PrintAvoirFournisseurAsync(avoirId);
360+
}
361+
362+
private async Task PrintAvoirFournisseurAsync(int avoirFournisseurId)
363+
{
364+
try
365+
{
366+
var pdfResult = await PrintAvoirFournisseurService.GenerateAvoirFournisseurPdfAsync(avoirFournisseurId, _cancellationTokenSource.Token);
367+
368+
if (pdfResult.IsSuccess)
369+
{
370+
var printOptions = new PrintOptions
371+
{
372+
Mode = PrintMode.Download,
373+
FileName = $"AvoirFournisseur_{avoirFournisseurId}.pdf",
374+
DocumentType = DocumentTypes.AvoirFournisseur,
375+
DocumentId = avoirFournisseurId
376+
};
377+
378+
await PrintServiceInfra.PrintAsync(pdfResult.Value, printOptions, _cancellationTokenSource.Token);
379+
NotificationService.Notify(new NotificationMessage
380+
{
381+
Severity = NotificationSeverity.Success,
382+
Summary = Localizer["success"],
383+
Detail = "L'avoir fournisseur a été généré avec succès."
384+
});
385+
}
386+
else
387+
{
388+
NotificationService.Notify(new NotificationMessage
389+
{
390+
Severity = NotificationSeverity.Error,
391+
Summary = Localizer["error"],
392+
Detail = pdfResult.Errors.FirstOrDefault()?.Message ?? "Erreur lors de la génération du PDF."
393+
});
394+
}
395+
}
396+
catch (Exception ex)
397+
{
398+
logger.LogError(ex, "Error printing avoir fournisseur {Id}", avoirFournisseurId);
399+
NotificationService.Notify(new NotificationMessage
400+
{
401+
Severity = NotificationSeverity.Error,
402+
Summary = Localizer["error"],
403+
Detail = $"Erreur lors de l'impression: {ex.Message}"
404+
});
405+
}
406+
}
407+
339408
private async Task FetchAvoirFournisseur()
340409
{
341410
var avoirFournisseurIdToLoad = id;

src/WebApps/TunNetCom.SilkRoadErp.Sales.WebApp/Components/Pages/AvoirFournisseur/AvoirFournisseurList.razor

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
@inject Radzen.NotificationService NotificationService
2424
@inject DialogService DialogService
2525
@using TunNetCom.SilkRoadErp.Sales.Domain.Entites
26+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Reports.AvoirFournisseur
27+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Infrastructure
28+
@inject PrintAvoirFournisseurService PrintAvoirFournisseurService
29+
@inject IPrintService PrintServiceInfra
2630

2731
<div class="invoices-list-container">
2832
<div class="search-header">
@@ -162,10 +166,18 @@
162166
</RadzenDataGridColumn>
163167
<RadzenDataGridColumn TItem="AvoirFournisseurBaseInfo"
164168
Title="@Localizer["actions_label"]"
165-
Width="100px"
169+
Width="140px"
166170
Sortable="false"
167171
Filterable="false">
168172
<Template Context="item">
173+
<RadzenButton Icon="print"
174+
ButtonStyle="ButtonStyle.Secondary"
175+
Variant="Variant.Flat"
176+
Size="ButtonSize.Small"
177+
Click="@(() => PrintAvoirFournisseurAsync(item.Id))"
178+
Title="Imprimer"
179+
AriaLabel="Imprimer"
180+
Style="margin-right: 4px;" />
169181
<RadzenButton Icon="edit"
170182
ButtonStyle="ButtonStyle.Primary"
171183
Variant="Variant.Flat"
@@ -613,6 +625,54 @@
613625
NavigationManager.NavigateTo($"/AddOrUpdateAvoirFournisseur/{id}");
614626
}
615627

628+
private async Task PrintAvoirFournisseurAsync(int id)
629+
{
630+
try
631+
{
632+
var pdfResult = await PrintAvoirFournisseurService.GenerateAvoirFournisseurPdfAsync(id, default);
633+
634+
if (pdfResult.IsSuccess)
635+
{
636+
var item = avoirsFournisseurList.FirstOrDefault(x => x.Id == id);
637+
var numLabel = item != null ? item.NumAvoirChezFournisseur.ToString() : id.ToString();
638+
var printOptions = new PrintOptions
639+
{
640+
Mode = PrintMode.Download,
641+
FileName = $"AvoirFournisseur_{numLabel}.pdf",
642+
DocumentType = DocumentTypes.AvoirFournisseur,
643+
DocumentId = id
644+
};
645+
646+
await PrintServiceInfra.PrintAsync(pdfResult.Value, printOptions, default);
647+
NotificationService.Notify(new NotificationMessage
648+
{
649+
Severity = NotificationSeverity.Success,
650+
Summary = Localizer["Success"],
651+
Detail = "L'avoir fournisseur a été généré avec succès."
652+
});
653+
}
654+
else
655+
{
656+
NotificationService.Notify(new NotificationMessage
657+
{
658+
Severity = NotificationSeverity.Error,
659+
Summary = Localizer["Erreur"],
660+
Detail = pdfResult.Errors.FirstOrDefault()?.Message ?? "Erreur lors de la génération du PDF."
661+
});
662+
}
663+
}
664+
catch (Exception ex)
665+
{
666+
_logger.LogError(ex, "Error printing avoir fournisseur {Id}", id);
667+
NotificationService.Notify(new NotificationMessage
668+
{
669+
Severity = NotificationSeverity.Error,
670+
Summary = Localizer["Erreur"],
671+
Detail = $"Erreur lors de l'impression: {ex.Message}"
672+
});
673+
}
674+
}
675+
616676
private string GetStatusStyle(int statut)
617677
{
618678
return statut == 1

src/WebApps/TunNetCom.SilkRoadErp.Sales.WebApp/Components/Pages/FactureAvoirFournisseur/FactureAvoirFournisseurList.razor

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
@inject NavigationManager NavigationManager
2222
@inject ITagsApiClient TagsService
2323
@inject DialogService DialogService
24+
@inject Radzen.NotificationService NotificationService
25+
@using TunNetCom.SilkRoadErp.Sales.Domain.Entites
26+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Reports.FactureAvoirFournisseur
27+
@using TunNetCom.SilkRoadErp.Sales.WebApp.PrintEngine.Infrastructure
28+
@inject PrintFactureAvoirFournisseurService PrintFactureAvoirFournisseurService
29+
@inject IPrintService PrintServiceInfra
2430

2531
<div class="invoices-list-container">
2632
<div class="search-header">
@@ -123,10 +129,18 @@
123129
</RadzenDataGridColumn>
124130
<RadzenDataGridColumn TItem="FactureAvoirFournisseurBaseInfo"
125131
Title="@Localizer["actions_label"]"
126-
Width="100px"
132+
Width="140px"
127133
Sortable="false"
128134
Filterable="false">
129135
<Template Context="item">
136+
<RadzenButton Icon="print"
137+
ButtonStyle="ButtonStyle.Secondary"
138+
Variant="Variant.Flat"
139+
Size="ButtonSize.Small"
140+
Click="@(() => PrintFactureAvoirFournisseurAsync(item.Id))"
141+
Title="Imprimer"
142+
AriaLabel="Imprimer"
143+
Style="margin-right: 4px;" />
130144
<RadzenButton Icon="edit"
131145
ButtonStyle="ButtonStyle.Primary"
132146
Variant="Variant.Flat"
@@ -482,5 +496,53 @@
482496
await Callback(new LoadDataArgs { Skip = 0, Top = pageSize });
483497
}
484498
}
499+
500+
private async Task PrintFactureAvoirFournisseurAsync(int id)
501+
{
502+
try
503+
{
504+
var pdfResult = await PrintFactureAvoirFournisseurService.GenerateFactureAvoirFournisseurPdfAsync(id, default);
505+
506+
if (pdfResult.IsSuccess)
507+
{
508+
var item = facturesAvoirFournisseurList.FirstOrDefault(x => x.Id == id);
509+
var numLabel = item != null ? item.NumFactureAvoirFourSurPage.ToString() : id.ToString();
510+
var printOptions = new PrintOptions
511+
{
512+
Mode = PrintMode.Download,
513+
FileName = $"FactureAvoirFournisseur_{numLabel}.pdf",
514+
DocumentType = DocumentTypes.FactureAvoirFournisseur,
515+
DocumentId = id
516+
};
517+
518+
await PrintServiceInfra.PrintAsync(pdfResult.Value, printOptions, default);
519+
NotificationService.Notify(new NotificationMessage
520+
{
521+
Severity = NotificationSeverity.Success,
522+
Summary = Localizer["Success"],
523+
Detail = "La facture avoir fournisseur a été générée avec succès."
524+
});
525+
}
526+
else
527+
{
528+
NotificationService.Notify(new NotificationMessage
529+
{
530+
Severity = NotificationSeverity.Error,
531+
Summary = Localizer["Erreur"],
532+
Detail = pdfResult.Errors.FirstOrDefault()?.Message ?? "Erreur lors de la génération du PDF."
533+
});
534+
}
535+
}
536+
catch (Exception ex)
537+
{
538+
_logger.LogError(ex, "Error printing facture avoir fournisseur {Id}", id);
539+
NotificationService.Notify(new NotificationMessage
540+
{
541+
Severity = NotificationSeverity.Error,
542+
Summary = Localizer["Erreur"],
543+
Detail = $"Erreur lors de l'impression: {ex.Message}"
544+
});
545+
}
546+
}
485547
}
486548

0 commit comments

Comments
 (0)