Skip to content

Commit

Permalink
Merge branch 'dev' into SD-160_AddJIT20
Browse files Browse the repository at this point in the history
  • Loading branch information
jkosternl committed Dec 13, 2024
2 parents 226eb69 + a41b072 commit 345bc68
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,34 @@ private static JsonNode getShipmentLocationTypeCode(JsonNode body, @NonNull Stri
return issues;
});

static final JsonContentCheck CHECK_CARGO_GROSS_WEIGHT_CONDITIONS =
JsonAttribute.allIndividualMatchesMustBeValid(
"Check Cargo Gross Weight conditions",
mav -> mav.submitAllMatching("requestedEquipments.*"),
(nodeToValidate, contextPath) -> {
var issues = new LinkedHashSet<String>();
var cargoGrossWeight = nodeToValidate.path("cargoGrossWeight");
if (cargoGrossWeight.isMissingNode() || cargoGrossWeight.isNull()) {
var commodities = nodeToValidate.path("commodities");
if (!(commodities.isMissingNode() || commodities.isNull()) && commodities.isArray()) {
AtomicInteger commodityCounter = new AtomicInteger(0);
StreamSupport.stream(commodities.spliterator(), false)
.forEach(
commodity -> {
var commodityGrossWeight = commodity.path("cargoGrossWeight");
int currentCommodityCount = commodityCounter.getAndIncrement();
if (commodityGrossWeight.isMissingNode()
|| commodityGrossWeight.isNull()) {
issues.add(
"The '%s' must have cargo gross weight at commodities position %s"
.formatted(contextPath, currentCommodityCount));
}
});
}
}
return issues;
});

private static <T, O> Supplier<T> delayedValue(Supplier<O> cspSupplier, Function<O, T> field) {
return () -> {
var csp = cspSupplier.get();
Expand Down Expand Up @@ -611,6 +639,7 @@ private static void generateScenarioRelatedChecks(List<JsonContentCheck> checks,
VALIDATE_SHIPPER_MINIMUM_REQUEST_FIELDS,
VALIDATE_DOCUMENT_PARTY,
NATIONAL_COMMODITY_TYPE_CODE_VALIDATION,
CHECK_CARGO_GROSS_WEIGHT_CONDITIONS,
JsonAttribute.atLeastOneOf(
JsonPointer.compile("/expectedDepartureDate"),
JsonPointer.compile("/expectedArrivalAtPlaceOfDeliveryStartDate"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.dcsa.conformance.standards.booking.checks;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.dcsa.conformance.core.check.JsonContentCheck;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Set;

import static org.dcsa.conformance.core.toolkit.JsonToolkit.OBJECT_MAPPER;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class BookingChecksTest {

private ObjectNode booking;
private ObjectNode requestedEquipment;
private ArrayNode requestedEquipments;
private ObjectNode commodity;
private ArrayNode commodities;

@BeforeEach
void setUp() {
booking = OBJECT_MAPPER.createObjectNode();
requestedEquipment = OBJECT_MAPPER.createObjectNode();
requestedEquipments = OBJECT_MAPPER.createArrayNode();
commodity = OBJECT_MAPPER.createObjectNode();
commodities = OBJECT_MAPPER.createArrayNode();
}

@Test
void testCargoGrossWeightPresentAtRequestedEquipment_valid() {
requestedEquipment.set("cargoGrossWeight", OBJECT_MAPPER.createObjectNode());
requestedEquipments.add(requestedEquipment);
booking.set("requestedEquipments", requestedEquipments);
JsonContentCheck check = BookingChecks.CHECK_CARGO_GROSS_WEIGHT_CONDITIONS;
Set<String> error = check.validate(booking);
assertTrue(error.isEmpty());
}

@Test
void testCargoGrossWeightMissingAtRequestedEquipmentNoCommodities_valid() {

booking.set("requestedEquipments", requestedEquipments);
JsonContentCheck check = BookingChecks.CHECK_CARGO_GROSS_WEIGHT_CONDITIONS;
Set<String> errors = check.validate(booking);
assertTrue(errors.isEmpty());
}

@Test
void testCargoGrossWeightMissingAtRequestedEquipmentPresentAtCommodities_valid() {
commodity.set("cargoGrossWeight", OBJECT_MAPPER.createObjectNode());
commodities.add(commodity);
requestedEquipment.set("commodities", commodities);
requestedEquipments.add(requestedEquipment);
booking.set("requestedEquipments", requestedEquipments);
JsonContentCheck check = BookingChecks.CHECK_CARGO_GROSS_WEIGHT_CONDITIONS;
Set<String> errors = check.validate(booking);
assertTrue(errors.isEmpty());
}

@Test
void testCargoGrossWeightMissingInRequestedEquipmentsAndAlsoInCommodities_invalid() {

commodities.add(commodity);
requestedEquipment.set("commodities", commodities);
requestedEquipments.add(requestedEquipment);
booking.set("requestedEquipments", requestedEquipments);

JsonContentCheck check = BookingChecks.CHECK_CARGO_GROSS_WEIGHT_CONDITIONS;
Set<String> errors = check.validate(booking);
assertEquals(1, errors.size());
assertTrue(
errors.contains(
"The 'requestedEquipments[0]' must have cargo gross weight at commodities position 0"));
}

@Test
void testCargoGrossWeightMissingInRequestedEquipmentsAndInOneOfTheCommodities_invalid() {

ObjectNode commodity2 = OBJECT_MAPPER.createObjectNode();
commodity.set("cargoGrossWeight", OBJECT_MAPPER.createObjectNode());
commodities.add(commodity2);
commodities.add(commodity);
requestedEquipment.set("commodities", commodities);
requestedEquipments.add(requestedEquipment);
booking.set("requestedEquipments", requestedEquipments);
JsonContentCheck check = BookingChecks.CHECK_CARGO_GROSS_WEIGHT_CONDITIONS;
Set<String> errors = check.validate(booking);
assertEquals(1, errors.size());
assertTrue(
errors.contains(
"The 'requestedEquipments[0]' must have cargo gross weight at commodities position 0"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ info:
version: 3.0.0
title: DCSA eBL Issuance API
description: |
<h1>DCSA OpenAPI specification for the issuance of an electronic Bill of Lading (eBL) via an eBL Solution Provider</h1>
<h1>DCSA OpenAPI specification for the issuance of an electronic Bill of Lading (referred to as `eBL`) via an eBL Solution Provider</h1>
This API is intended as an API between a carrier and a EBL Solution Platform.
This API is intended as an API between a carrier and a eBL Solution Platform.
The EBL Solution Provider is to implement
The eBL Solution Provider is to implement
PUT /v3/ebl-issuance-requests
for the carrier to call and the carrier is to implement
POST /v3/ebl-issuance-responses
for the EBL Solution Provider to call.
for the eBL Solution Provider to call.
When the document is to be surrendered, it should happen via a version of the [DCSA EBL Surrender](https://app.swaggerhub.com/apis-docs/dcsaorg/DCSA_EBL_SUR/3.0.0) API.
When the document is to be surrendered, it should happen via a version of the [DCSA eBL Surrender](https://app.swaggerhub.com/apis-docs/dcsaorg/DCSA_EBL_SUR/3.0.0) API.
### API Design & Implementation Principles
This API follows the guidelines defined in version 2.1 of the API Design & Implementation Principles which can be found on the [DCSA Developer page](https://developer.dcsa.org/api_design)
Expand All @@ -29,34 +29,34 @@ info:
Please look at the following implementation guide for how to create [Digital Signatures](https://developer.dcsa.org/implementing-digital-signatures-for-transport-documents).
### Changelog and GitHub
For a changelog, please click [here](https://github.com/dcsaorg/DCSA-OpenAPI/tree/master/ebl/v3/issuance#v300). Please [create a GitHub issue](https://github.com/dcsaorg/DCSA-OpenAPI/issues/new) if you have any questions/comments.
For a changelog, please click [here](https://github.com/dcsaorg/DCSA-OpenAPI/tree/master/ebl/v3/issuance#v300). If you have any questions, feel free to [Contact Us](https://dcsa.org/get-involved/contact-us).
API specification issued by [DCSA.org](https://dcsa.org/).
license:
name: Apache 2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
contact:
name: Digital Container Shipping Association (DCSA)
url: 'https://dcsa.org'
email: [email protected]
tags:
- name: Issuance EBL
- name: Issuance eBL
description: |
Issuance EBL **implemented** by EBL Solution Platform
Issuance eBL **implemented** by eBL Solution Platform
- name: Issuance Response
description: |
Issuance Response **implemented** by carrier
paths:
/v3/ebl-issuance-requests:
put:
tags:
- Issuance EBL
- Issuance eBL
operationId: put-ebl-issuance-requests
summary: Request issuance of an EBL
summary: Request issuance of an eBL
description: |
Submit a transport document (EBL) for issuance
Submit a transport document (eBL) for issuance
**This endPoint is to be implemented by an EBL Solution Provider for the carrier to call**
**This endPoint is to be implemented by an eBL Solution Provider for the carrier to call**
parameters:
- $ref: '#/components/parameters/Api-Version-Major'
requestBody:
Expand All @@ -78,7 +78,7 @@ paths:
description: |
An Issuance Request is made with a `Transport Document Reference` (TDR), that was used previously to request the issuance of a `Transport Document` (TD). The document is either already issued or an TD with the same TDR.
The eBL platform will inform the carrier when the carrier needs to act on this document again. If the issuance is pending, then the carrier will be notified via the DCSA_EBL_ISS_RSP API once the issuance process completes. If the issuance has already succeeded, the eBL platform will notify the carrier when there is a surrender request via the DCSA_EBL_SUR API.
The eBL platform will inform the carrier when the carrier needs to act on this document again. If the issuance is pending, then the carrier will be notified via the `/v3/ebl-issuance-responses` endPoint once the issuance process completes. If the issuance has already succeeded, the eBL platform will notify the carrier when there is a surrender request via the DCSA_EBL_SUR API.
headers:
API-Version:
$ref: '#/components/headers/API-Version'
Expand Down Expand Up @@ -124,7 +124,7 @@ paths:
description: |
Submit a response to a carrier issuance request.
**This endPoint is to be implemented by a carrier for the EBL Solution Provider to call**
**This endPoint is to be implemented by a carrier for the eBL Solution Provider to call**
parameters:
- $ref: '#/components/parameters/Api-Version-Major'
requestBody:
Expand Down Expand Up @@ -402,7 +402,7 @@ components:
pattern: ^\S+$
maxLength: 4
description: |
The EBL platform of the transaction party.
The eBL platform of the transaction party.
The value **MUST** be one of:
- `WAVE` (Wave)
- `CARX` (CargoX)
Expand Down Expand Up @@ -3235,7 +3235,7 @@ components:
issuanceResponseCode:
type: string
description: |
The platforms verdict on the issuance of the EBL identified by the `transportDocumentReference`
The platforms verdict on the issuance of the eBL identified by the `transportDocumentReference`
Options are:
- `ISSU`: The document was successfully `ISSU` and successfully delivered to the initial possessor.
Expand Down Expand Up @@ -3274,7 +3274,7 @@ components:
description: |
An object to capture where the original Transport Document (`Bill of Lading`) will be issued.
The location can be specified as one of `UN Location Code` or `CountryCode`.
**Condition:** The location can be specified as one of `UN Location Code` or `CountryCode`, but not both.
properties:
locationName:
type: string
Expand Down Expand Up @@ -3450,7 +3450,7 @@ components:
pattern: ^\S(?:.*\S)?$
maxLength: 35
description: |
Reference number assigned to an `Import License` or permit, issued by countries exercising import controls that athorizes the importation of the articles stated in the license. The `Import License` must be valid at time of arrival.
Reference number assigned to an `Import License` or permit, issued by countries exercising import controls that authorizes the importation of the articles stated in the license. The `Import License` must be valid at time of arrival.
example: EMC007123
issueDate:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.EXEMPT_PACKAGE_CODES;
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.MODE_OF_TRANSPORT;
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.NATIONAL_COMMODITY_CODES;
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.PARTY_FUNCTION_CODE;
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.PARTY_FUNCTION_CODE_HBL;
import static org.dcsa.conformance.standards.ebl.checks.EblDatasets.REQUESTED_CARRIER_CLAUSES;


Expand Down Expand Up @@ -666,6 +668,19 @@ private static Consumer<MultiAttributeValidator> allDg(Consumer<MultiAttributeVa
JsonAttribute.mustBeAbsent(SI_REQUEST_SEND_TO_PLATFORM)),
JsonAttribute.mustBeAbsent(SI_REQUEST_SEND_TO_PLATFORM));

static final JsonRebaseableContentCheck VALID_PARTY_FUNCTION =
JsonAttribute.allIndividualMatchesMustBeValid(
"The partyFunction in OtherDocumentParty is valid",
mav -> mav.submitAllMatching("documentParties.other.*.partyFunction"),
JsonAttribute.matchedMustBeDatasetKeywordIfPresent(PARTY_FUNCTION_CODE));

static final JsonRebaseableContentCheck VALID_PARTY_FUNCTION_HBL =
JsonAttribute.allIndividualMatchesMustBeValid(
"The partyFunction in OtherDocumentParty of houseBillOfLadings is valid",
mav ->
mav.submitAllMatching("houseBillOfLadings.*.documentParties.other.*.partyFunction"),
JsonAttribute.matchedMustBeDatasetKeywordIfPresent(PARTY_FUNCTION_CODE_HBL));

private static final List<JsonContentCheck> STATIC_SI_CHECKS = Arrays.asList(
JsonAttribute.mustBeDatasetKeywordIfPresent(
SI_REQUEST_SEND_TO_PLATFORM,
Expand All @@ -684,6 +699,8 @@ private static Consumer<MultiAttributeValidator> allDg(Consumer<MultiAttributeVa
ROUTING_OF_CONSIGNMENT_COUNTRIES_CHECK,
VALID_REQUESTED_CARRIER_CLAUSES,
BUYER_AND_SELLER_CONDITIONAL_CHECK,
VALID_PARTY_FUNCTION,
VALID_PARTY_FUNCTION_HBL,
ONLY_EBLS_CAN_BE_NEGOTIABLE,
EBL_AT_MOST_ONE_COPY_WITHOUT_CHARGES,
EBL_AT_MOST_ONE_COPY_WITH_CHARGES,
Expand Down Expand Up @@ -811,7 +828,8 @@ private static Consumer<MultiAttributeValidator> allDg(Consumer<MultiAttributeVa
JsonAttribute.matchedMustBeDatasetKeywordIfPresent(MODE_OF_TRANSPORT)
),
NOTIFY_PARTIES_REQUIRED_IN_NEGOTIABLE_BLS,
TLR_CC_T_COMBINATION_UNIQUE
TLR_CC_T_COMBINATION_UNIQUE,
VALID_PARTY_FUNCTION
);

public static final JsonContentCheck SIR_REQUIRED_IN_NOTIFICATION = JsonAttribute.mustBePresent(SI_NOTIFICATION_SIR_PTR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,8 @@ public class EblDatasets {
"INTRANSITCLAUSE"
);

public static final KeywordDataset PARTY_FUNCTION_CODE =
KeywordDataset.staticDataset("SCO", "DDR", "DDS", "COW", "COX", "CS", "MF", "WH");
public static final KeywordDataset PARTY_FUNCTION_CODE_HBL =
KeywordDataset.staticDataset("DDR", "DDS", "CS", "MF", "WH");
}
Loading

0 comments on commit 345bc68

Please sign in to comment.