Activity Log Controller Source Code
Activity Log Controller Source Code
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 () 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 () 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”) 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
Text
REDACTED – ATELIER TECHNOLOGY LIM
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 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
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] !== 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>