edifact-generator icon indicating copy to clipboard operation
edifact-generator copied to clipboard

COHAOR

Open davidvandertuijn opened this issue 7 years ago • 16 comments

Does this libary support COHAOR (Container special handling order message) , UN/EDIFACT D17B ? https://service.unece.org/trade/untdid/d17b/trmd/cohaor_c.htm

davidvandertuijn avatar Nov 21 '18 12:11 davidvandertuijn

Yes, it can be done, but I haven't implemented it (I don't use that message). You can write a class similar to the existing ones which outputs the data in the Cohaor message format, take a look to the Iftmbf, or the other container related messages (for example Coparn..) If you do, please send a pull request, or write me :)

sabas avatar Nov 21 '18 13:11 sabas

They need to be added, because they are implied in the specification. An interchange (UNB/UNZ) wraps one or more messages (UNH/UNT), in the interchange header you add inforrmation like the sender and the receiver.

sabas avatar Nov 21 '18 14:11 sabas

What u think so far?

https://github.com/davidvandertuijn/edifact-generator/commit/62868a048190d685683c3895033a7b978c69ac1e

I have noticed the *Segment() functions in your Message Class however, i find the functionality limited and created new classses for the segments i need.

Test Script:

$sMessageReferenceNumber = 'ROW'.str_pad(1, 11, 0, STR_PAD_LEFT);

$oCohaor = (new \EDI\Generator\Cohaor($sMessageReferenceNumber))
    // ->setMessageSender('IC', '', 'JOHN DOE')
    // ->setMessageSenderInformation('EM', '[email protected]')
;

// Segment Group 2 : Name And Address

$oNameAndAddress = (new \EDI\Generator\Cohaor\NameAndAddress())
    ->setPartyFunctionCodeQualifier('ZZZ')
    ->setPartyIdentificationDetails('Floro Webdevelopment')
    ->setNameAndAddress([
        'Floro Webdevelopment', // line 1 .. 5
        'Westblaak 180', // line 2 .. 5
        '3012KC' // line 3 .. 5
    ])
    ->setCityName('Rotterdam')
    ->setPostalIdentificationCode('3012KC')
    ->setCountryIdentifier('NL')
;

// Segment Group 2

$oCohaor->addSegmentGroup(2, [
    $oNameAndAddress->compose()
]);

// Segment Group 4 : Equipment Details

$oEquipmentDetails = (new \EDI\Generator\Cohaor\EquipmentDetails())
    ->setEquipmentTypeCodeQualifier('AM') // Refrigerated Container
    ->setEquipmentIdentification('TSTU1807438')
    ->setEquipmentSizeAndType(4532, '', 5, '')
    ->setEquipmentSupplierCode('')
    ->setEquipmentStatusCode('')
    ->setFullOrEmptyIndicatorCode(6)
    ->setMarkingInstructionsCode('ZZZ')
;

// Segment Group 4 : Reference

$oReference = (new \EDI\Generator\Cohaor\Reference())
    ->setReferenceCodeQualifier('BN')
    ->setReferenceIdentifier('ABCDEF123456')
;

// Segment Group 4 : Date Time Period

$oDateTimePeriod = (new \EDI\Generator\Cohaor\DateTimePeriod())
    ->setDateOrTimeOrPeriodFunctionCodeQualifier(7) // Effective from date/time
    ->setDateOrTimeOrPeriodText('201811011000')
    ->setDateOrTimeOrPeriodFormatCode(203) // CCYYMMDDHHMM
;

// Segment Group 4 : Place Location Identification

$oPlaceLocationIdentification1 = (new \EDI\Generator\Cohaor\PlaceLocationIdentification())
    ->setLocationFunctionCodeQualifier('9') // Place of loading
    ->setLocationIdentification('BEZEE','','','')
;

$oPlaceLocationIdentification2 = (new \EDI\Generator\Cohaor\PlaceLocationIdentification())
    ->setLocationFunctionCodeQualifier('11') // Place of discharge
    ->setLocationIdentification('NLRTM','','','')
;

// Segment Group 4 : Free Text

$oFreeText1 = (new \EDI\Generator\Cohaor\FreeText())
    ->setTextSubjectCodeQualifier('AAA') // Good Description
    ->setTextLiteral(['FROZEN PULP FICTION'])
;

$oFreeText2 = (new \EDI\Generator\Cohaor\FreeText())
    ->setTextSubjectCodeQualifier('AEJ') // Controlled atmosphere
    ->setTextLiteral(['YES'])
;

$oFreeText3 = (new \EDI\Generator\Cohaor\FreeText())
    ->setTextSubjectCodeQualifier('AEB') // Temperature control instructions
    ->setTextLiteral(['DEFROSTING'])
;

// Segment Group 4 : Measurements

$oMeasurements = (new \EDI\Generator\Cohaor\Measurements())
    ->setMeasurementPurposeCodeQualifier('AAE') // Measurement
    ->setMeasurementDetails('AAO') // Humidity
    ->setValueRange('PER', 99 )
;

// Segment Group 4

$oCohaor->addSegmentGroup(4, [
    $oEquipmentDetails->compose(),
    $oReference->compose(),
    $oDateTimePeriod->compose(),
    $oPlaceLocationIdentification1->compose(),
    $oPlaceLocationIdentification2->compose(),
    $oFreeText1->compose(),
    $oFreeText2->compose(),
    $oFreeText3->compose(),
    $oMeasurements->compose()
]);

// Segment Group 11 : Temperature

$oTemperature = (new \EDI\Generator\Cohaor\Temperature())
    ->setTemperatureTypeCodeQualifier('SET') // SET
    ->setTemperatureSetting('12.00','CEL')
;

// Segment Group 11 : Range Details

$oRangeDetails = (new \EDI\Generator\Cohaor\RangeDetails())
    ->setRangeTypeCodeQualifier('5') // Temperature range
    ->setMeasurementUnitCode('CEL')
    ->setRangeMinimumQuantity('10.00')
    ->setRangeMaximumQuantity('14.00')
;

// Segment Group 11 : Control Total

$oControlTotal = (new \EDI\Generator\Cohaor\ControlTotal())
    ->setControlTotalTypeCodeQualifier('16')
    ->setControlTotalQuantity('1')
;

// Segment Group 11

$oCohaor->addSegmentGroup(11, [
    $oTemperature->compose(),
    $oRangeDetails->compose(),
    $oControlTotal->compose()
]);

/**
 * Message Function Code.
 *
 * @var $iMessageFunctionCode
 * @see https://service.unece.org/trade/untdid/d17b/tred/tred1225.htm
 * @comment 9 : Original
 */

$iMessageFunctionCode = 9;

/**
 * Document Name Code.
 *
 * @var $iDocumentNamecode
 * @see https://service.unece.org/trade/untdid/d17b/tred/tred1001.htm
 *
 * @comment 292 : Inspection request
 * @comment 297 : Instruction to collect
 * @comment 293 : Inspection report
 */

$iDocumentNamecode = 293;

$sDocumentIdentifier = '123456'; // your unique document identifier.

$oCohaor->compose($iMessageFunctionCode, $iDocumentNamecode, $sDocumentIdentifier);

$aComposed = $oCohaor->getComposed();

echo (new \EDI\Encoder($aComposed, false))->get();

davidvandertuijn avatar Nov 22 '18 15:11 davidvandertuijn

I like your approach, using a class per segment was an idea I had as well but never explored. Do you think could be worthy if (some of?) those segments could be moved in root (example: Segment\DateTimePeriod) and other classes may be refactored to use those eventually extending if a particular message differs? What you think could be the impact of creating lots of class instances (example: a full vessel generating a bayplan or a loading order of a thousand of containers)?

sabas avatar Nov 22 '18 16:11 sabas

  1. Moving the segment classes to more general directory sound like a good idea, would u preffer 'segment' or 'segments' (plural) ?
  2. The impact of creating lots of class instances depends on the size of the data, which consumes memory. If the memory is not sufficient i would suggest sending multiple messages or batch processing.

davidvandertuijn avatar Nov 22 '18 18:11 davidvandertuijn

I've no strong opinion on the plural vs singular issue, singular could be chosen for uniformity with the existing Interchange / Message (and perhaps an abstract Segment class to act as a template?) but feel free to continue as your best practice works :)

sabas avatar Nov 22 '18 21:11 sabas

What u think so far? https://github.com/davidvandertuijn/edifact-generator/commit/e080e43c226407cbc722dbab8875a7a500c2d4fe

I moved the segments to a seperate directory.

The message content however contains trailing data elements and their leading separators:

array:6 [
    0 => "LOC"
    1 => "9"
    2 => array:4 [
      0 => "NLMSV"
      1 => ""
      2 => ""
      3 => ""
    ]
    3 => []
    4 => []
    5 => ""
]
LOC+9+NLMSV:::+++'

I've added a reduce() function in de Message class. Do you have a snippet which recursively walk an Array and remove the empty values from the end of the Array? this would be very helpfull.

davidvandertuijn avatar Nov 23 '18 09:11 davidvandertuijn

I did that by checking if the value was set during the compose() run (and similarly in the segment functions), example https://github.com/php-edifact/edifact-generator/blob/master/src/Generator/Coparn.php#L293 and https://github.com/php-edifact/edifact-generator/blob/master/src/Generator/Coparn.php#L240

sabas avatar Nov 23 '18 11:11 sabas

The architecture issue is when using the check on null values is that you must specify each value, even when they are empty else the EDI output is invalid for example:

Wrong

$oFreeText = (new \EDI\Generator\Segment\FreeText())
    ->setTextSubjectCodeQualifier('AEB')
    ->setTextLiteral(['DEFROSTING'])
    ->compose();

FTX+AEB+DEFROSTING'

Good

$oFreeText = (new \EDI\Generator\Segment\FreeText())
    ->setTextSubjectCodeQualifier('AEB')
    ->setFreeTextFunctionCode('') // must be empty
    ->setTextReference('') // must be empty
    ->setTextLiteral(['DEFROSTING'])
    ->compose();

FTX+AEB+++DEFROSTING'

How you think of this approach ?

davidvandertuijn avatar Dec 03 '18 08:12 davidvandertuijn

So if one person forgets setTextReference we throw some error?

sabas avatar Dec 03 '18 14:12 sabas

In the first approach i set all values 'empty' by default, but then i have trailing data elements and their leading separators. In the second approach i set all values NULL by default, but then is must specify empty values.

Difficult to throw an Error in the second approach, because you must check, does the value in the segment has previous required values. There is no procedure available in php-edifact to validate the $aComposed Array of a segment for example ?

davidvandertuijn avatar Dec 03 '18 15:12 davidvandertuijn

I can't think of a smart way to do it without checking every value... :-/

sabas avatar Dec 06 '18 23:12 sabas

Maybe later, is it possible you merge these changes for now ?

davidvandertuijn avatar Dec 13 '18 11:12 davidvandertuijn

Done!

sabas avatar Dec 13 '18 13:12 sabas

@davidvandertuijn anche user reports this, Could you please check (I'm not with my computer till Friday...)?

Fatal error: Declaration of EDI\Generator\Vermas::compose($msgStatus = 5, $documentCode = 749) must be compatible with EDI\Generator\Message::compose(?string $sMessageFunctionCode, ?string $sDocumentNameCode, ?string $sDocumentIdentifier): EDI\Generator\Message in /home/edifact-generator-master/src/Generator/Vermas.php on line 5

sabas avatar Jan 30 '19 18:01 sabas

https://github.com/php-edifact/edifact-generator/issues/4

davidvandertuijn avatar Jan 30 '19 20:01 davidvandertuijn