0% found this document useful (0 votes)
5 views50 pages

Activity Log Controller Source Code

The document contains proprietary source code for Atelier Technology Limited's Activity Log system, including controllers, models, and services. Key functionalities include retrieving activity logs, searching for user and company IDs, and handling SQS events for processing messages. The code is structured with various classes and methods to manage activity log entries and responses efficiently.

Uploaded by

muhaamadwaleed68
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views50 pages

Activity Log Controller Source Code

The document contains proprietary source code for Atelier Technology Limited's Activity Log system, including controllers, models, and services. Key functionalities include retrieving activity logs, searching for user and company IDs, and handling SQS events for processing messages. The code is structured with various classes and methods to manage activity log entries and responses efficiently.

Uploaded by

muhaamadwaleed68
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

PROPRIETARY SOURCE CODE EXPORT

Company: Atelier Technology Limited


Domain: Activity Log
Export Date: 2025-11-05 13:59:33
Copyright: Atelier Technology Limited

FILE: ActivityLog\ActivityLog\Controllers\[Link]
namespace [Link]
{
[ApiController]
[Authorize]
[Route("[controller]")]
public class ActivityLogController : Controller
{
private readonly IActivityLogRepository activityLogRepository;
private readonly IGetActivityLogsRequestValidator getActivityLogsRequestValidator;
public ActivityLogController(IActivityLogRepository activityLogRepository,
IGetActivityLogsRequestValidator getActivityLogsRequestValidator)
{
[Link] = activityLogRepository ?? throw new
ArgumentNullException(nameof(activityLogRepository));
[Link] = getActivityLogsRequestValidator ?? throw new
ArgumentNullException(nameof(getActivityLogsRequestValidator));
}
[HttpGet]
[ProducesResponseType(typeof(Representation<GetActivityLogsResponseModel>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Representation<GetActivityLogsResponseModel>), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Get([FromQuery] GetActivityLogsRequestModel requestModel)
{
if (![Link](requestModel)) return [Link]();
var response = await [Link](requestModel, [Link]());
return [Link](new Representation<GetActivityLogsResponseModel> { Value = response });
}
[HttpGet("search")]
[ProducesResponseType(typeof(Representation<GetActivityLogSearchResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Representation<GetActivityLogSearchResponse>), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetCompanyAndUserIdsToSearch([FromQuery] GetActivityLogsSearchRequest requestModel)
{
var response = await [Link](requestModel,
[Link]());
return [Link](new Representation<GetActivityLogSearchResponse> { Value = response });
}
[HttpGet("by-version")]
[ProducesResponseType(typeof(Representation<ActivityLogEntryModel>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Representation<ActivityLogEntryModel>), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetByVersion([FromQuery] GetActivityLogByVersionRequest request)
{
if (![Link](request)) return BadRequest();
var response = await [Link](request, [Link]());
return Ok(new Representation<ActivityLogEntryModel> { Value = response });
}
}
}
END FILE: ActivityLog\ActivityLog\Controllers\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class ActivityLogEntryModel
{
public string Id { get; set; }
public string MessageId { get; set; }
public string MessageType { get; set; }
public string ObjectId { get; set; }
public string SizeId { get; set; }
public DateTime Timestamp { get; set; }
public string UserId { get; set; }
public string CompanyId { get; set; }
public string CorrelationId { get; set; }
public int? Version { get; set; }
public ActivityLogContent Content { get; set; }
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class GetActivityLogByVersionRequest : GetActivityLogBaseRequest
{
public int Version { get; set; }
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class GetActivityLogsRequestModel : GetActivityLogBaseRequest
{
public string SearchTerm { get; set; }
public ICollection<Guid> UserIds { get; set; }
public ICollection<Guid> CompanyIds { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public GetActivityLogsRequestModel()
{
UserIds ??= [Link]<Guid>();
CompanyIds ??= [Link]<Guid>();
}
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class GetActivityLogsResponseModel
{
public IEnumerable<ActivityLogEntryModel> Data { get; set; }
public int TotalPages { get; set; }
public int TotalRecords { get; set; }
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class GetActivityLogSearchResponse
{
public IEnumerable<string> AvailableCompaniesIds { get; set; }
public IEnumerable<string> AvailableUsersIds { get; set; }
public GetActivityLogSearchResponse()
{
}
public GetActivityLogSearchResponse(IEnumerable<string> availableCompaniesIds, IEnumerable<string> availableUsersIds)
{
AvailableCompaniesIds = availableCompaniesIds;
AvailableUsersIds = availableUsersIds;
}
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]
namespace [Link]
{
public class GetActivityLogsSearchRequest : GetActivityLogBaseRequest
{
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\[Link]

FILE: ActivityLog\ActivityLog\Models\ActivityLog\Abstract\[Link]
namespace [Link]
{
public abstract class GetActivityLogBaseRequest
{
public string SizeId { get; set; }
}
}
END FILE: ActivityLog\ActivityLog\Models\ActivityLog\Abstract\[Link]

FILE: ActivityLog\ActivityLog\Services\ActivityLog\[Link]
namespace [Link]
{
public class ActivityLogRepository : IActivityLogRepository
{
private readonly ActivityLogDbContext dbContext;
public ActivityLogRepository(ActivityLogDbContext dbContext)
{
[Link] = dbContext;
}
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20
FILE: ActivityLog\[Link]\Entities\[Link]
namespace [Link]
{
public class ActivityLogEntryDescription
{
public string ActivityLogId { get; set; }
public int Sequence { get; set; }
public string Description { get; set; }
}
}
END FILE: ActivityLog\[Link]\Entities\[Link]

FILE: ActivityLog\[Link]\Entities\[Link]
namespace [Link]
{
public class ProcessedMessage
{
public string MessageId { get; set; }
public DateTime ProcessedDate { get; set; }
}
}
END FILE: ActivityLog\[Link]\Entities\[Link]

FILE: ActivityLog\[Link]\[Link]
namespace [Link]
{
public class ActivityLogContent
{
public string Summary { get; set; }
public string ActivityType { get; set; }
public string[] Description { get; set; }
}
}
END FILE: ActivityLog\[Link]\[Link]
FILE: ActivityLog\[Link]\[Link]
namespace [Link]
{
public class ActivityLogProcessor : IActivityLogProcessor
{
private readonly ILogger<ActivityLogProcessor> logger;
private readonly IHandleSqsEvent handleSqsEvent;
private readonly string emptyGuid = [Link]();
private readonly IOptions<ActivityLogProcessorOptions> options;
private readonly IServiceProvider serviceProvider;
private int numberOfMessagesIgnored;
private int numberOfMessagesProcessed;
private int numberOfActivityLogRecordsCreated;
public ActivityLogProcessor(IServiceProvider serviceProvider, ILogger<ActivityLogProcessor> logger, IHandleSqsEvent
handleSqsEvent, IOptions<ActivityLogProcessorOptions> options)
{
[Link] = logger ?? throw new ArgumentNullException(nameof(logger));
[Link] = handleSqsEvent ?? throw new ArgumentNullException(nameof(handleSqsEvent));
[Link] = options ?? throw new ArgumentNullException(nameof(options));
[Link] = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
public async Task Handler(SQSEvent e)
{
var timer = new Stopwatch();
[Link]();
if ([Link] == null)
{
[Link]("Message received was not a valid SQS message. The message has been consumed but not
processed.");
return;
}
[Link] = 0;
[Link] = 0;
[Link] = 0;
var numberOfMessagesReceived = [Link];
var response = await [Link]([Link], e, async (record, _) => await
[Link](record),
[Link]);
foreach (var failure in [Link](_ => !_.IsSuccessful))
{
// Log failures.
[Link](
[Link],
"Could not process message {MessageId}. {Message}.",
[Link],
[Link]);
}
[Link]();
[Link](
"Lambda Received: {numberOfMessagesReceived}, Ignored: {numberOfMessagesIgnored}, Processed:
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

Text
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

Text
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”)REDACTED


TRADE SECRET
– ATELIER
UNDER
TECHNOLOGY
37 C.F.R. § 202.20
LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOU REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20
REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”U

Text
REDACTED – ATELIER TECHNOLOGY LIM

REDACTED – ATELIER TECHNOLOG

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIM

REDACTED – ATELIER TECHNOLOGY.

REDACTED – ATELIER TECHNOLOGY. REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE S
Text

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20

REDACTED – ATELIER TECHNOLOGY


REDACTED – ATELIER TECHNOLOGY LIMITED (DBA “LOUPE”) TRADE SECRET UNDER 37 C.F.R. § 202.20
{
public class TetherToGrid : ITetherToGrid
{
public bool TetherToStonesEnabled { get; set; }
public bool TetherToLabourSettingsEnabled { get; set; }
public bool TetherToPreciousMetalsEnabled { get; set; }
}
}
END FILE: ActivityLog\[Link]\EventTypes\EventDetails\[Link]
FILE: ActivityLog\[Link]\EventTypes\EventDetails\[Link]
namespace [Link]
{
public class WithdrawnSize : IWithdrawnSize
{
public string Id { get; set; }
}
}
END FILE: ActivityLog\[Link]\EventTypes\EventDetails\[Link]
FILE: enterprisev3-web\src\app\products\activity\activity-log-item\[Link]
<div class="activity-log-item">
<div class="row">
<div class="col-auto pr-0">
<app-avatar [image]="customer?.profileImageThumb" size="md"></app-avatar>
</div>
<div class="col">
<div class="activity-log-item__title">
<span *ngIf="customer?.fullName" class="font-weight-bold">
{{ customer?.fullName }}
</span>
<span
*ngIf="company?.name || customer?.jobTitle"
class="font-size-sm ml-xxs"
>
{{ company?.name }}
<span *ngIf="company?.name && customer?.teams">| </span>
<span *ngIf="customer?.teams">
{{ customer?.[Link](', ') }}
</span>
</span>
</div>
<div class="activity-log-item__content">
<p
*ngFor="
let paragraph of [Link];
let last = last
"
[ngClass]="{ 'mb-0': last }"
>
{{ paragraph }}
</p>
<p class="mb-0" *ngIf="[Link]">
<a
[routerLink]="versionUrl"
[id]="'versionLink_' + [Link]"
target="_blank"
>{{
'products.activity_log.view_version'
| translate: { version: [Link] }
}}</a
>
<ng-container
*ngIf="
[Link] &&
!isPartOfSet
"
>
|
<ng-container
*ngIf="
status === [Link];
else comparisonLink
"
>
<ng-container
*ngIf="
currentSubmissionVersionID === [Link];
else disabledLink
"
>
<ng-container
*ngTemplateOutlet="currentSubmission"
></ng-container>
</ng-container>
<ng-template #disabledLink>
<span
[popover]="
'products.activity_log.compare_with_current_disabled'
| translate
"
[id]="'comparisonLink_' + [Link]"
class="
border-0
btn btn-link
d-inline
disabled
p-0
text-decoration-underline
"
triggers="mouseenter:mouseleave"
>
{{ 'products.activity_log.compare_with_current' | translate }}
</span>
</ng-template>
</ng-container>
<ng-template #comparisonLink>
<ng-container
*ngIf="
currentSubmissionVersionID === [Link];
else activeLink
"
>
<ng-container
*ngTemplateOutlet="currentSubmission"
></ng-container>
</ng-container>
<ng-template #activeLink>
<a
[routerLink]="comparisonUrl"
[id]="'comparisonLink_' + [Link]"
(click)="scrollPageToTop()"
>{{
'products.activity_log.compare_with_current' | translate
}}</a
>
</ng-template>
</ng-template>
</ng-container>
</p>
</div>
<div class="activity-log-item__timestamp font-size-sm mt-xs">
{{ [Link] | date: 'dd MMM yyyy hh:mm a' }}
</div>
</div>
<div
class="activity-log-item__status activity-log-item__status--{{
[Link] | lowercase
}} col-auto text-right font-weight-bold"
>
{{ [Link] }}
</div>
</div>
</div>
<ng-template #currentSubmission>
<span [id]="'currentSubmission_' + [Link]">{{
'products.activity_log.current_submission' | translate
}}</span>
</ng-template>
END FILE: enterprisev3-web\src\app\products\activity\activity-log-item\[Link]

FILE: enterprisev3-web\src\app\products\activity\activity-log-item\[Link]
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { SpinnerVisibilityService } from 'ng-http-loader';
import { ActivityLogEntry } from 'src/app/api/activity-log/models';
import {
AtelierCompanyType,
CompanyPublicProfile,
CompanySchemaResponse,
CostSubmissionStatus,
} from 'src/app/api/models';
import { AppConfigService } from 'src/app/[Link]';
import { AuthService } from 'src/app/shared/services/[Link]';
import { DataSubmissionService } from 'src/app/shared/services/[Link]';
import {
ActivityLogDataService,
ActivityLogUser,
} from '../services/[Link]';
@Component({
selector: 'app-activity-log-item',
templateUrl: './[Link]',
styleUrls: ['./[Link]'],
})
export class ActivityLogItemComponent implements OnInit {
@Input() public activityLogItem: ActivityLogEntry;
@Input() public status: CostSubmissionStatus;
@Input() public currentSubmissionVersionID: number;
public company: CompanyPublicProfile;
public comparisonUrl: string;
{{ 'products.cost_analysis.metal.metal_title' | translate }}
</th>
<th id="costSubmissionMetalColour" scope="col">
{{ 'products.cost_analysis.[Link]' | translate }}
</th>
<th id="costSubmissionMetalNickelContent" scope="col">
{{ 'products.cost_analysis.metal.nickel_content' | translate }}
</th>
<th
id="costSubmissionMetalMetalLossPercentage"
scope="col"
class="text-right"
>
{{ 'products.cost_analysis.metal.metal_loss' | translate }} %
</th>
<th class="text-right" id="costSubmissionMetalInvoiceMetalTitle" scope="col">
{{
'products.cost_analysis.metal.invoiced_metal_title' | translate
}}
</th>
<th id="costSubmissionMetalNetWeight" scope="col" class="text-right">
{{ 'products.cost_analysis.metal.net_metal_weight' | translate }}
</th>
<th
id="costSubmissionMetalFixAllowance"
scope="col"
class="text-right"
>
{{ 'products.cost_analysis.metal.fix_allowance' | translate }}
</th>
<th id="costSubmissionMetalTroyOz" scope="col" class="text-right">
{{ 'products.cost_analysis.metal.troy_oz' | translate }}
</th>
<th
id="costSubmissionMetalCostPerGram"
scope="col"
class="text-right"
>
{{ 'products.cost_analysis.metal.metal_cost_per_gram' | translate }}
</th>
<th id="costSubmissionMetalMetalCost" scope="col" class="text-right">
{{ 'products.cost_analysis.metal.metal_cost' | translate }}
</th>
<th id="costSubmissionMetalEdit" scope="col"></th>
</tr>
</thead>
<tbody>
<!-- Main -->
<tr *ngIf="mainMetalRowsVisible">
<th
class="table__header"
colspan="13"
id="costSubmissionMetalComponent"
>
<i class="icon-dps-component" aria-hidden="true"></i
>{{ 'products.cost_analysis.[Link]' | translate }}
</th>
</tr>
<ng-container *ngFor="let metal of [Link]; index as i">
<ng-container
*ngTemplateOutlet="
metalTemplate;
context: {
arrayName: 'main',
index: i,
metal: metal,
hide:
[Link] !== null &&
+[Link] === 0 &&
[Link] !== null &&
+[Link] === 0
}
"
></ng-container>
</ng-container>
<!-- Chains -->
<tr *ngIf="[Link] && [Link]">
<th class="table__header" colspan="13" id="costSubmissionMetalChain">
<i class="icon-dps-chain" aria-hidden="true"></i
>{{ 'products.cost_analysis.[Link]' | translate }}
</th>
</tr>
<ng-container *ngFor="let metal of [Link]; index as i">
<ng-container
*ngTemplateOutlet="
metalTemplate;
context: {
arrayName: 'chains',
headers: 'costSubmissionMetalChain',
index: i,
metal: metal
}
"
{{ [Link][activeIndex].quantityType }}
</p>
<p class="font-size-sm mb-0">
{{ [Link][activeIndex].name }}
{{
getMetalTitle(
[Link][activeIndex].metal,
[Link][activeIndex].metalTitle
)
}}
</p>
</div>
</div>
<ng-container
*ngIf="[Link][activeIndex].isPrecious; else nonPrecious"
>
<!-- Colour -->
<div
*ngIf="
[Link][activeIndex].alloyDetails &&
[Link][activeIndex].[Link] > 1
"
class="row mb-xs"
>
<div class="col">
<label for="colour">
{{ 'products.cost_analysis.[Link]' | translate }}
<span class="form-label__required-indicator">*</span>
</label>
<ng-select
(change)="onChangeColour($event)"
[items]="[Link][activeIndex].alloyDetails"
[placeholder]="'common.please_select' | translate"
bindLabel="colour"
bindValue="colour"
class="custom"
formControlName="colour"
labelForId="colour"
></ng-select>
<form-input hidden control="isIndexed"></form-input>
</div>
</div>
<!-- Metal Loss -->
<div class="row mb-xs">
<div class="col">
<form-input
(change)="onChangeLoss()"
[dropSpecialCharacters]="false"
[label]="'products.cost_analysis.metal.metal_loss'"
[labelWarning]="
showNullValueIndexedWarning
? ('products.cost_analysis.no_approved_value_for_indexed_component'
| translate)
: null
"
[validation]="false"
control="loss"
mask="separator.3"
separatorLimit="10"
suffix="%"
></form-input>
</div>
</div>
<!-- Invoiced Metal Title -->
<div class="row mb-xs">
<div class="col">
<form-input
(change)="onChangeInvoicedMetalTitle()"
[dropSpecialCharacters]="true"
control="invoicedMetalTitle"
label="products.cost_analysis.metal.invoiced_metal_title"
mask="separator.2"
separatorLimit="10000000"
thousandSeparator=","
></form-input>
</div>
</div>
<!-- Fixing Allowance -->
<div class="row">
<div class="col">
<form-input
[dropSpecialCharacters]="
[Link] ===
[Link]
"
[label]="'[Link].chain_detail.fixing_allowance'"
[mask]="
[Link] ===
[Link]
? 'percent.2'
: 'separator.2'
"
[prefixString]="
[Link] ===
[Link]
? currencySymbol
: ''
"
[restrictMinMax]="
[Link] ===
[Link]
"
[separatorLimit]="
[Link] ===
[Link]
? '100000000'
: ''
"
[suffix]="
[Link] ===
[Link]
? '%'
: ''
"
[validation]="false"
control="fixingAllowance"
max="100"
min="0"
thousandSeparator=","
></form-input>
</div>
</div>
</ng-container>
<ng-template #nonPrecious>
<!-- Net Weight -->
<div class="row mb-xs">
<div class="col">
<form-input
control="netWeight"
label="products.cost_analysis.metal.net_metal_weight"
></form-input>
</div>
</div>
<!-- Metal Cost -->
<div class="row">
<div class="col">
<form-input
[dropSpecialCharacters]="true"
control="metalCalculatedValue"
label="products.cost_analysis.metal.metal_cost"
mask="separator.2"
[prefixString]="currencySymbol"
separatorLimit="100000"
thousandSeparator=","
></form-input>
</div>
</div>
</ng-template>
</ng-container>
</ng-container>
</div>
<div class="modal-footer">
<button
(click)="onBack()"
*ngIf="[Link] > 1 && activeIndex > 0"
class="btn btn-lg btn-link ml-0 pl-0 mr-auto"
id="costSubmissionMetalModalBack"
type="button"
>
{{ '[Link]' | translate }}
</button>
<button
(click)="onHideModal()"
class="btn btn-lg btn-link"
id="costSubmissionMetalModalCancel"
type="button"
>
{{ '[Link]' | translate }}
</button>
<button
(click)="onNext()"
*ngIf="[Link] > 1 && activeIndex + 1 !== [Link]"
class="btn btn-lg btn-outline-primary"
id="costSubmissionMetalModalNext"
type="button"
>
{{ '[Link]' | translate }}
</button>
<button
class="btn btn-lg btn-primary"
id="costSubmissionMetalModalSaveAndExit"
type="submit"
[disabled]="[Link]"
>
{{ '[Link].save_and_exit' | translate }}
</button>
@Output() public productCostModified: EventEmitter<{
data: CreateProductCostRequest;
modifiedKey: string;
costAnalysis: ProductCostAnalysisResponse;
}> = new EventEmitter<{
data: CreateProductCostRequest;
modifiedKey: string;
costAnalysis: ProductCostAnalysisResponse;
}>();
public activeIndex = 0;
public allMetalsCalculated: boolean;
public currency: CurrencyResponse;
public currencySymbol: string;
public isOpen = false;
public mainForm: UntypedFormGroup;
public mainMetalRowsVisible: boolean;
public metals: MetalCostsResponse;
public metalFixingAllowanceType: string;
public modalRef: BsModalRef;
public userIsCustomer =
[Link]().companyType ===
[Link];
public readonly costSubmissionStatus: typeof CostSubmissionStatus =
CostSubmissionStatus;
public readonly metalQuantityType: typeof MetalQuantityType =
MetalQuantityType;
public readonly tradingParameterValueType: typeof TradingParameterValueType =
TradingParameterValueType;
public tetherWarningParams: TetherWarningParams;
public metalValuesHaveChanged: boolean;
public atLeastOneChange: boolean;
private metalOptions: Array<MetalOptionSchema>;
private subscriptions: Subscription = new Subscription();
private tetherToSourcingGrid: TetherToSourcingGridRequest;
@ViewChild('metalModal') private metalModal: TemplateRef<any>;
@ViewChild('tetherWarningModal') private tetherWarningModal: TemplateRef<any>;
constructor(
public dataSubmissionService: DataSubmissionService,
private accordionsService: CostSubmissionAccordionsService,
private authService: AuthService,
private formBuilder: UntypedFormBuilder,
private globalMessagesService: GlobalMessagesService,
private metalOptionsService: MetalOptionsService,
private modalMessagesService: ModalMessagesService,
private modalService: BsModalService,
private productCostService: ProductCostService,
private translateService: TranslateService
) {}
public ngOnInit(): void {
[Link](
[Link]().subscribe({
next: (res: RepresentationOfIEnumerableOfMetalOptionSchema) => {
[Link] = [Link];
},
error: () => [Link]('common.server_error'),
})
);
[Link](
[Link](
(res: CostSubmissionAccordionOpenState) => {
if ([Link] === [Link]) {
[Link] = [Link];
}
}
)
);
[Link] = [Link];
// Compare each metal from current and snapshot to determine if anything changed
if ([Link] && [Link]) {
const currentMetals = {
...[Link],
chains: [Link]([Link]),
findings: [Link]([Link]),
main: [Link]([Link]),
originalTotalNetWeight: [Link]?.toFixed(2),
totalCost: [Link]?.toFixed(2),
};
const versionMetals = {
...[Link],
chains: [Link](
[Link]
),
findings: [Link](
[Link]
),
main: [Link](
[Link]
),
originalTotalNetWeight:
[Link]?.toFixed(2),
totalCost: [Link]?.toFixed(2),
};
[Link] =
[Link](currentMetals) !== [Link](versionMetals);
}
}
public ngOnChanges(changes: SimpleChanges): void {
if (
changes &&
[Link] &&
[Link]
) {
[Link]();
}
}
public ngOnDestroy(): void {
[Link]();
}
public onIsOpenChange(event: boolean): void {
[Link] = event;
[Link]({
accordion: [Link],
isOpen: event,
});
}
public get mainFormArray(): UntypedFormArray {
return [Link]('array') as UntypedFormArray;
}
public get showNullValueIndexedWarning(): boolean {
const control = [Link]([Link]);
return (
[Link]
.tetherToPreciousMetalsEnabled &&
[Link]('isIndexed').value &&
[Link]('preApprovedLoss').value === null &&
formatFixingAllowance(
+[Link]('fixingAllowance').value,
[Link],
false
) === [Link]('preApprovedFixingAllowance').value
);
}
public getMetalName(metal: string): string {
if (![Link] || ![Link] || !metal) {
return;
}
return [Link](
(metalOption: MetalOptionSchema) => [Link] === metal
).name;
}
public getMetalTitle(metal: string, metalTitle: number): string {
if (
![Link] ||
![Link] ||
!metal ||
!metalTitle
) {
return;
}
return [Link]
.find((metalOption: MetalOptionSchema) => [Link] === metal)
.[Link](
(title: MetalTitleOptionValueSchema) => [Link] === metalTitle
).title;
}
public onShowModal(arrayName: string, index: number): void {
[Link] = index;
switch (arrayName) {
case 'main':
[Link]();
break;
case 'chains':
[Link]();
break;
case 'findings':
[Link]();
break;
}
}
public onChangeColour(event: MetalColourWithNickelContent): void {
[Link]([Link]);
[Link](
calculateInvoicedMetalTitle(+[Link], [Link])
);
[Link]();
}
public onChangeLoss(): void {
if (![Link]) {
[Link](0);
}
if ([Link]) {
[Link](
calculateInvoicedMetalTitle(+[Link], [Link])
);
}
}
public onChangeInvoicedMetalTitle(): void {
if (![Link]) {
[Link]([Link]);
}
if ([Link]) {
[Link](
+(
(1 - [Link] / +[Link]) *
100
).toFixed(3)
);
}
}
public onNext(): void {
[Link]++;
}
public onBack(): void {
[Link]--;
}
public onProceedTether(): void {
if ([Link]) {
[Link] = false;
}
[Link](true);
}
public onSubmitMainForm(bypassTetherWarningModal?: boolean): void {
if (!bypassTetherWarningModal && [Link]()) {
[Link]();
return;
}
const metals = [Link](
(metal: MetalCostResponse, index: number) => {
const formGroup = [Link](index) as UntypedFormGroup;
const lossValue = [Link]('loss').value as number;
const fixingAllowanceValue = [Link]('fixingAllowance')
.value as number;
const metalRequest = {
...metal,
...[Link],
loss: lossValue,
currencyId: [Link],
fixingAllowance: formatFixingAllowance(
fixingAllowanceValue,
[Link],
false
),
} as MetalCostRequest;
if ([Link]) {
[Link] = calculateMetalCost(
metalRequest,
[Link],
[Link]
);
}
return metalRequest;
}
);
const data: CreateProductCostRequest = {
...[Link](),
metals,
...[Link],
};
const createOrUpdateObservable: Observable<RepresentationOfProductCostAnalysisResponse> =
[Link]
? [Link](data)
: [Link](data);
[Link](
[Link](
(res: RepresentationOfProductCostAnalysisResponse) => {
if (res && [Link]) {
// Update the table
[Link] = [Link](
(metal: MetalCostResponse, index: number) => {
return { ...metal, ...[Link][index] };
}
);
[Link]<MetalCostsResponse>(
'metals',
[Link]
);
[Link]({
data: data,
modifiedKey: 'tetherToSourcingGrid',
costAnalysis: [Link],
});
[Link]({
data: data,
modifiedKey: 'metals',
costAnalysis: [Link],
});
[Link]();
} else {
[Link](
[Link]('common.error_save')
);
}
},
(error: HttpErrorResponse) => {
[Link]([Link]);
}
)
);
}
public onHideModal(): void {
[Link]();
}
private get metalTitle(): number {
return +[Link][[Link]].metalTitle;
}
private get lossControl(): AbstractControl {
return [Link]([Link]).get('loss');
}
private get colourControl(): AbstractControl {
return [Link]([Link]).get('colour');
}
private get nickelContentControl(): AbstractControl {
return [Link]([Link]).get('nickelContent');
}
private get invoicedMetalTitleControl(): AbstractControl {
return [Link]([Link]).get('invoicedMetalTitle');
}
private getMetals(): void {
if ([Link] && [Link]) {
[Link] = [Link]([Link]([Link]));
[Link] =
[Link];
[Link] = [Link];
// Set the currency symbol
[Link] = getCurrencySymbol(
[Link],
'wide'
);
// Set whether "Component" table heading should be visible
[Link] = ![Link](
(metal: MetalCostResponse) =>
[Link] !== null &&
+[Link] === 0 &&
[Link] !== null &&
+[Link] === 0
);
[Link]();
}
}
private hideModal(): void {
if ([Link]) {
[Link]();
[Link] = 0;
}
}
private onShowMetalModal(): void {
[Link] = [Link]({
array: [Link]([]),
});
[Link]((metal: MetalCostResponse) => {
[Link] = parseFloat([Link]?.toFixed(2));
[Link](
[Link]({
metalCalculatedValue: [
[Link],
![Link]
? [
[Link](999999.99),
[Link](0),
[Link],
]
: [Link],
],
colour: [
[Link],
[Link] && [Link] > 1
? [Link]
: [Link],
],
invoicedMetalTitle: [
[Link]
? [Link] || [Link]
: null,
[Link]
? [
[Link](
+([Link] / (1 - 99.99 / 100)).toFixed(2)
),
[Link]([Link]),
[Link],
]
: [Link],
],
loss: [
[Link] ?? 0,
[Link]
? [[Link](99.999), [Link](0), [Link]]
: [Link],
],
fixingAllowance: [
formatFixingAllowance(
[Link],
[Link]
),
[
[Link](0),
[Link](
[Link] ===
[Link]
? 100
: 999999999.99
),
[Link] ? [Link] : [Link],
],
],
netWeight: [
{ value: [Link], disabled: true },
![Link] ? [Link] : [Link],
],
nickelContent: [[Link]],
isIndexed: [[Link]],
preApprovedFixingAllowance: [[Link]],
preApprovedInvoicedMetalTitle: [[Link]],
preApprovedLoss: [[Link]],
preApprovedMetalCalculatedValue: [
[Link],
],
id: [[Link]],
})
);
});
[Link] = [Link]([Link]);
}
private onShowChainDetailModal() {
[Link] = [Link](ProductChainDetailModalComponent, {
initialState: {
allSubmissionsData: [Link],
},
});
}
private onShowFindingDetailModal() {
[Link] = [Link](
ProductCostEditFindingModalComponent,
{
initialState: {
allSubmissionsData: [Link],
},
}
);
}
private verifyAllMetalsCalculated(): void {
[Link] = [Link]
.concat([Link])
.concat([Link])
.every((metal: MetalCostResponse) => [Link] != null);
}
private getIndexedMetal(): void {
const activeMainMetal = [Link][[Link]];
const activeMainFormArray = [Link]([Link]);
[Link](
[Link]
.ProductCostGetIndexedMetal({
customerCompanyId: [Link],
fixingAllowanceType: [Link],
currencyId: [Link],
metalKey: [Link],
metalTitleValue: +[Link],
colour: <string>[Link],
nickelContent: <string>[Link],
})
.subscribe(
({
value: { fixingAllowance, loss, isIndexed },
}: RepresentationOfMetalIndexingResponse) => {
const preApprovedInvoicedMetalTitle = calculateInvoicedMetalTitle(
loss,
+[Link]
);
const preApprovedMetalCalculatedValue = calculateMetalCost(
{
fixingAllowance: fixingAllowance,
netWeight: [Link],
invoicedMetalTitle: preApprovedInvoicedMetalTitle,
},
[Link],
[Link]
);
[Link]({
fixingAllowance: formatFixingAllowance(
fixingAllowance,
[Link]
),
isIndexed: isIndexed,
loss: loss ?? 0,
preApprovedFixingAllowance: fixingAllowance,
preApprovedLoss: loss,
preApprovedInvoicedMetalTitle: preApprovedInvoicedMetalTitle,
preApprovedMetalCalculatedValue: preApprovedMetalCalculatedValue,
invoicedMetalTitle: preApprovedInvoicedMetalTitle,
calculatedMetalValue: preApprovedMetalCalculatedValue
});
}
)
);
}
private initTetherWarning(): boolean {
[Link] = false;
[Link] = {};
// Get status of Raw Materials > Precious Metal BoM tier Tether to Grid toggle switch
const rawMaterialPreciousMetalTetherToGridEnabled: boolean =
[Link]
.tetherToPreciousMetalsEnabled;
// Get metals indexed against Precious Metals grid only
const metalsIndexed: MetalCostResponse[] = [Link]
.filter((metal: MetalCostResponse) => [Link])
.map((item: MetalCostResponse) => ({ ...item }));
if (rawMaterialPreciousMetalTetherToGridEnabled && [Link]) {
// Use `some` so we break the loop when the first non-matching metal is found
[Link]((metal: MetalCostResponse) => {
// Get the form control for the stone currently being looped over
const formValue = [Link](
(control: AbstractControl) => [Link]('id').value === [Link]
).value;
// List of indexable fields to extract from the complete objects
const indexableFields = ['fixingAllowance', 'colour'];
if ([Link] !== null) {
[Link]('loss', 'invoicedMetalTitle');
}
[Link] = formatFixingAllowance(
[Link],
[Link],
true
);
// Extract the indexable fields only for comparison, and cast everything as strings to prevent type differences
const formIndexableFields: Partial<StoneCostResponse> = [Link](
{},
...[Link]((k: string) => ({
[k]: formValue[k]?.toString(),
}))
);
const metalIndexableFields: Partial<StoneCostResponse> = [Link](
{},
...[Link]((k: string) => ({ [k]: metal[k]?.toString() }))
);
// Stringify the objects so we can do a simple comparison
[Link] =
[Link](formIndexableFields) !==
[Link](metalIndexableFields);
// Return a boolean value to stop the loop if true
return [Link];
});
}
if ([Link]) {
[Link] = TetherWarningType.OFF_SINGLE_GRID;
[Link] = ProductCostTierType.PRECIOUS_METAL;
[Link] = 'precious_metals';
}
// Return the boolean value to trigger showing the tether warning modal
if ([Link]) {
return true;
}
}
private showTetherWarningModal(): void {
[Link]();
[Link]([Link]);
}
private transformMetalsForComparison(
arr: Array<MetalCostResponse>
): Array<MetalCostResponse> {
if (![Link]) {
return [];
}
return [Link]((metal: MetalCostResponse) => {
const {
alloyDetails,
guide,
name,
preApprovedFixingAllowance,
| translate
| forceToLines
"
></th>
<th scope="col" class="col-1 text-right">
{{ 'products.bill_of_materials.stone_detail.min' | translate }}
</th>
<th scope="col" class="col-1 text-right">
{{ 'products.bill_of_materials.stone_detail.max' | translate }}
</th>
<th scope="col" class="col-1 text-right">
{{ 'products.bill_of_materials.stone_detail.quantity' | translate }}
</th>
<th scope="col" class="col-1 text-right">
{{
'products.bill_of_materials.stone_detail.carat_subtotal' | translate
}}
</th>
<th scope="col" class="col-1 text-right">
{{ 'products.bill_of_materials.stone_detail.min' | translate }}
</th>
<th scope="col" class="col-1 text-right">
{{ 'products.bill_of_materials.stone_detail.max' | translate }}
</th>
<th
scope="col"
class="col-1 text-right"
[innerHTML]="
'products.bill_of_materials.stone_detail.modal.duty_rate'
| translate
| forceToLines
"
></th>
<th scope="col" class="col-1 text-right">
{{
'products.bill_of_materials.stone_detail.modal.duty_cost' | translate
}}
</th>
<th scope="col" class="col-1">
{{
'products.bill_of_materials.stone_detail.modal.setting_type'
| translate
}}
</th>
<th scope="col" class="col-1">
{{
'products.bill_of_materials.stone_detail.modal.setting_method'
| translate
}}
</th>
<th scope="col" class="col-1">
{{
'products.bill_of_materials.stone_detail.modal.setting_reference'
| translate
}}
</th>
<th scope="col" class="col-1">
{{
'products.bill_of_materials.stone_detail.modal.setting_location'
| translate
}}
</th>
<th scope="col" class="col-1 text-right">
{{
'products.bill_of_materials.stone_detail.modal.setting_charge'
| translate
}}
</th>
<th
scope="col"
class="text-nowrap text-right"
[innerHTML]="
'products.bill_of_materials.stone_detail.modal.setting_cost_subtotal'
| translate
| forceToLines
"
></th>
<th scope="col" class="col-1 text-right">
{{
'products.bill_of_materials.stone_detail.stone_price_ppp_ppc'
| translate
}}
</th>
<th scope="col" class="col-1 text-right">
{{
'products.bill_of_materials.stone_detail.stone_cost_subtotal'
| translate
}}
</th>
</tr>
</thead>
<!-- Body -->
<tbody>

You might also like