Unit testing a function with a timestamp - php

I have an object function to send news to an API:
class Manager
{
public function __construct(GuzzleHttp\Client $client)
{
$this->client = $client;
}
public function uploadNews($title, $text, $timestamp = null)
{
// DEFAULT FOR PUBLISH TIMESTAMP IS SET IF VALUE IS NULL
$timestamp = $timestamp ?? time();
$requestBody = [
'header' => [
'Accept' => 'application/json',
],
'timeout' => 300,
'body' => [
'title' => $title,
'text' => $text,
'publish_date' => $timestamp,
]
];
return $this->client->request('POST', 'http://api/endpoint', $requestBody);
}
}
How do I write a PHPUnit unit test to test the final $request passed to the client's request() function is of the expected format, when the $timestamp is not set (the API expects a timestamp)? I've written a unit test. But is not ideal, since there could be a difference in the tow timestamps.
class ManagerTest extends \PHPUnit\Framework\TestCase
{
public function testCanUploadNewsWithoutTimestamp()
{
$expectedRequestBody = [
'header' => [
'Accept' => 'application/json',
],
'timeout' => 300,
'body' => [
'title' => 'News title',
'text' => 'News article sample text.',
'publish_date' => time(),
]
];
$guzzleMock = $this->createMock(GuzzleHttp\Client::class);
$guzzleMock->expects($this->once())
->method('request')
->with(
'POST',
'http://api/endpoint',
$expectedRequestBody
);
(new Manager($guzzleMock))->uploadNews(
'News title',
'News article sample text.'
);
}
}
This is my current test result:
Parameter 2 for invocation GuzzleHttp\Client::request('POST', 'http://api/endpoint', Array (...)) does not match expected value.
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
## ##
'body' => Array (
'title' => 'News title'
'text' => 'News article sample text.'
- 'publish_date' => 1574550178
+ 'publish_date' => 1574550179
)
)
Please note that the only thing I need to make sure is that the timestamp is passed with request. The value of the timestamp doesn't matter.
PS: I'm really new to Test Driven Development, so the answer might be obvious and I might still not know it.

Related

PHP / Docusign - Verify HMAC signature on completed event

I'm trying to secure my callback url when completed event is triggered.
My Controller:
public function callbackSubscriptionCompleted(
int $subscriptionId,
DocusignService $docusignService,
Request $request
) {
$signature = $request->headers->get("X-DocuSign-Signature-1");
$payload = file_get_contents('php://input');
$isValid = $docusignService->isValidHash($signature, $payload);
if (!$isValid) {
throw new ApiException(
Response::HTTP_BAD_REQUEST,
'invalid_subscription',
'Signature not OK'
);
}
return new Response("Signature OK", Response::HTTP_OK);
}
My DocusignService functions:
private function createEnvelope(Company $company, Subscription $subscription, LegalRepresentative $legalRepresentative, Correspondent $correspondent, $correspondents) : array
{
// ...
$data = [
'disableResponsiveDocument' => 'false',
'emailSubject' => 'Your Subscription',
'emailBlurb' => 'Subscription pending',
'status' => 'sent',
'notification' => [
'useAccountDefaults' => 'false',
'reminders' => [
'reminderEnabled' => 'true',
'reminderDelay' => '1',
'reminderFrequency' => '1'
],
'expirations' => [
'expireEnabled' => 'True',
'expireAfter' => '250',
'expireWarn' => '2'
]
],
'compositeTemplates' => [
[
'serverTemplates' => [
[
'sequence' => '1',
'templateId' => $this->templateId
]
],
'inlineTemplates' => [
[
'sequence' => '2',
'recipients' => [
'signers' => [
[
'email' => $legalRepresentative->getEmail(),
'name' => $legalRepresentative->getLastname(),
'recipientId' => '1',
'recipientSignatureProviders' => [
[
'signatureProviderName' => 'universalsignaturepen_opentrust_hash_tsp',
'signatureProviderOptions' => [
'sms' => substr($legalRepresentative->getCellphone(), 0, 3) == '+33' ? $legalRepresentative->getCellphone() : '+33' . substr($legalRepresentative->getCellphone(), 1),
]
]
],
'roleName' => 'Client',
'clientUserId' => $legalRepresentative->getId(),
'tabs' => [
'textTabs' => $textTabs,
'radioGroupTabs' => $radioTabs,
'checkboxTabs' => $checkboxTabs
]
]
]
]
]
]
]
],
'eventNotification' => [
"url" => $this->router->generate("api_post_subscription_completed_callback", [
"subscriptionId" => $subscription->getId()
], UrlGeneratorInterface::ABSOLUTE_URL),
"includeCertificateOfCompletion" => "false",
"includeDocuments" => "true",
"includeDocumentFields" => "true",
"includeHMAC" => "true",
"requireAcknowledgment" => "true",
"envelopeEvents" => [
[
"envelopeEventStatusCode" => "completed"
]
]
]
];
$response = $this->sendRequest(
'POST',
$this->getBaseUri() . '/envelopes',
[
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->getCacheToken()
],
json_encode($data)
);
}
public function isValidHash(string $signature, string $payload): bool
{
$hexHash = hash_hmac('sha256',utf8_encode($payload),utf8_encode($this->hmacKey));
$base64Hash = base64_encode(hex2bin($hexHash));
return $signature === $base64Hash;
}
I've created my hmac key in my Docusign Connect and i'm receiving the signature in the header and the payload but the verification always failed.
I've followed the Docusign documentation here
What's wrong ?
PS: Sorry for my bad english
Your code looks good to me. Make sure that you are only sending one HMAC signature. That way your hmacKey is the correct one.
As a check, I'd print out the utf8_encode($payload) and check that it looks right (it should be the incoming XML, no headers). Also, I don't think it should have a CR/NL in it at the beginning. That's the separator between the HTTP header and body.
Update
I have verified that the PHP code from the DocuSign web site works correctly.
The payload value must not contain either a leading or trailing newline. It should start with <?xml and end with >
I suspect that your software is adding a leading or trailing newline.
The secret (from DocuSign) ends with an =. It is a Base64 encoded value. Do not decode it. Just use it as a string.
Another update
The payload (the body of the request) contains zero new lines.
If you're printing the payload, you'll need to wrap it in <pre> since it includes < characters. Or look at the page source.
It contains UTF-8 XML such as
<?xml version="1.0" encoding="utf-8"?><DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0"><EnvelopeStatus><RecipientStatuses><RecipientStatus><Type>Signer</Type><Email>larry#worldwidecorp.us</Email><UserName>Larry Kluger</UserName><RoutingOrder>1</RoutingOrder><Sent>2020-08-05T03:11:13.057</Sent><Delivered>2020-08-05T03:11:27.657</Delivered><DeclineReason xsi:nil="true" /><Status>Delivered</Status><RecipientIPAddress>5.102.239.40</RecipientIPAddress><CustomFields /><TabStatuses><TabStatus><TabType>Custom</TabType><Status>Active</Status><XPosition>223</XPosition><YPosition>744....
We've done some more testing, and the line
$payload = file_get_contents('php://input');
should be very early in your script. The problem is that a framework can munge the php://input stream so it won't work properly thereafter.
Note this page from the Symfony site -- it indicates that the right way to get the request body is:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
$app->before(function (Request $request) {
$payload = $request->getContent();
hmac_verify($payload, $secret);
});
I would try to use the Symfony code instead of file_get_contents('php://input');

Amazon Pay SDK InvalidSignatureError

I'm integrating Amazon Pay php SDK from documentation, but getting this error.
Here's my php implementation code:
$amazonpay_config = array(
'public_key_id' => 'XXXXXXXX',
'private_key' => 'my_private_key_path',
'region' => 'US',
'sandbox' => true
);
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'checkoutSession' => null,
'payloadSign' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignPayload = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'checkoutSession' => json_decode($resultCheckOut['response']),
'payloadSign' => $resultSignPayload
];
return $requestResult;
}
Here's JS implementation code for generating Amazon Pay button.
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: jsonResult['checkoutSession'],
signature: jsonResult['payloadSign'],
publicKeyId: 'XXXXXXXXXXX'
}
});
Couple of problems with the code, mainly that you aren't passing the payload and signature to the front-end correctly. For the payload, you're using jsonResult['checkoutSession'], while it should be jsonResult['payloadSign']. This doesn't contain the payload though but from the PHP code it's apparently the signature that you have put in there. The full code sample should more like this (not tested).
Back-end:
$headers = array('x-amz-pay-Idempotency-Key' => uniqid());
$requestResult = [
'error' => 1,
'msg' => 'Error. Can not create checkout session.',
'signature' => null,
'payload' => null
];
$client = new Client($amazonpay_config);
$resultCheckOut = $client->createCheckoutSession($payload, $headers);
$resultSignature = $client->generateButtonSignature($payload);
if($resultCheckOut['status'] !== 201) {
return json_encode($requestResult, true);
}
else {
$requestResult = [
'error' => 0,
'msg' => null,
'signature' => $resultSignature,
'payload' => $payload
];
return json_encode($requestResult);
}
Front-end:
amazon.Pay.renderButton('#amazon-pay-btn', {
// set checkout environment
merchantId: 'XXXXXXXX',
ledgerCurrency: 'USD',
sandbox: true,
checkoutLanguage: 'en_US',
productType: 'PayOnly',
placement: 'Cart',
buttonColor: 'Gold',
createCheckoutSessionConfig: {
payloadJSON: JSON.stringify(jsonResult['payload']),
signature: jsonResult['signature'],
publicKeyId: 'XXXXXXXXXXX'
}
});
I'm not sure how you're passing $requestResult back to the front-end, potentially there's some additional JSON encoding/decoding required to get the right string. To prevent a signature mismatch error, please make sure that the payload string used for the signature generation in the backend, and the payload string assigned to the 'payloadJSON' parameter match exactly (especially pay attention to whitespaces, escape characters, line breaks, etc.).
Two comments about this issue:
I have defined the payload as an string (that's the way current AmazonPay doc states - Link).
$payload = '{
"webCheckoutDetails": {
"checkoutReviewReturnUrl": "https://www.example.com/review",
"checkoutResultReturnUrl": "https://www.example.com/result"
},
"storeId": "amzn1.application-oa2-client.XXXXXXXXX"
}';
instead of array
$payload = array(
'webCheckoutDetails' => array(
'checkoutReviewReturnUrl' => 'https://www.example.com/review',
'checkoutResultReturnUrl' => 'https://www.example.com/result'
),
'storeId' => 'amzn1.application-oa2-client.XXXXXXXXX'
);
The signature was created, but when rendering the button and clicking on it I get the following error.
Error Message: Signature Dk4qznkoiTVqjcY8Yn1l0iLbsoIj2pEAHWVtgYrphLtFXR9BKhJJPD53It4qYOswS1T/STYMHRy5jtCHGqvLntDjuy0MrhkpoHTpYEtwdOqGHA2qk+QnSGV5LoYldQ/UkAxSG7m8s2iOr11q2sWxUjrk2M3fgzAIxDeZRjJYeAr97eGANYva3jtGDfM6cJdieInBM4dEWWxKqGIh6HxOrY5K/ga26494vAwZAGvXRhZG48FOVp/XCr0mbu6V5pkEOzRJSc+hN5WKAs/c49UsfKPx75Ce7QbaBCZZT1UiczfyYx/mBuZuysUlGmnXPhLOLTPw4+SIizH/pOQyClOQyw== does not match signedString AMZN-PAY-RSASSA-PSS dfff7a87b93cfa78685a233f2dd59e18ad0451b2e3a90af11e500fcc0ceee924 for merchant XXXXXXXX
I was some time till I realized that this was the reason of the error. Actually, while writing this, the new lines in the string were the reason. If string is only in one line, it works.
The button only needs the payload and the signed payload. The $client->createCheckoutSession is not needed. More over, the checkoutSessionId of the resultCheckOut is different from the one obtained when the checkoutReviewReturnUrl is called.

Drupal 8 Custom Module - From dynamic data (API) to store at Fields (Content type) Drupal DB

I've created a custom module in Drupal 8 that grab some data from an API, and puts them in the Drupal DB creating a new table.
I want to add this data as the contents of a specific content type.
How can I do that?
here is my code :
<?php
/**
* Implements hook_cron().
*/
function ods_cron() {
$message = 'Cron run: ' . date('Y-m-d H:i:s');
$ods = \Drupal::service('ods.ods');
$conf = \Drupal::service('ods.ods_configuration_request');
if ($conf->isDevelopment()) {
// Development
$response_bond = beforeSendRequest($conf->devUrlExternalBond(), 'GET');
$response_mf = beforeSendRequest($conf->devUrlExternalMutualFund(), 'GET');
} else {
// Production
$parameters_bond = [
'headers' => $conf->headers(),
'authorization' => $conf->basicAuthorization(),
'data_post' => $conf->bodyBond(),
];
$parameters_mf = [
'headers' => $conf->headers(),
'authorization' => $conf->basicAuthorization(),
'data_post' => $conf->bodyMutualFund(),
];
$response_bond = beforeSendRequest($conf->urlExternalBond(), 'POST', $parameters_bond);
$response_mf = beforeSendRequest($conf->urlExternalMutualFund(), 'POST', $parameters_mf);
}
$raw_result_bond = json_decode($response_bond);
$raw_result_mf = json_decode($response_mf);
// Development
if ($conf->isDevelopment()) {
$raw_result_bond = json_decode($raw_result_bond[0]->field_bonds);
$raw_result_mf = json_decode($raw_result_mf[0]->field_api);
}
$BondsProductList = $raw_result_bond->BondsProductInqRs->BondsProductList;
$MFProductInqList = $raw_result_mf->MFProductInqRs->MFProductInqList;
// Bond data store to internal
if ($BondsProductList !== null) {
$bond_datas = [];
foreach ($BondsProductList as $row => $content) {
$bond_datas[] = [
'AskPrice' => number_format($content->AskPrice, 1, '.', ','),
'BidPrice' => number_format($content->BidPrice, 1, '.', ','),
'BuySettle' => number_format($content->BuySettle, 1, '.', ','),
'CouponFreqCode' => $content->CouponFreqCode,
'CouponFreqID' => number_format($content->CouponFreqID),
'CouponRate' => number_format($content->CouponRate, 2, '.', ','),
'IDCurrency' => $content->IDCurrency,
'LastCoupon' => $content->LastCoupon,
'MaturityDate' => $content->MaturityDate,
'MinimumBuyUnit' => number_format($content->MinimumBuyUnit),
'MultipleOfUnit' => number_format($content->MultipleOfUnit),
'NextCoupon' => $content->NextCoupon,
'Penerbit' => $content->Penerbit,
'ProductCode' => $content->ProductCode,
'ProductName' => $content->ProductName,
'ProductAlias' => $content->ProductAlias,
'RiskProfile' => $content->RiskProfile,
'SellSettle' => $content->SellSettle
];
}
$insert_data = $ods->setData(
'bond',
[
'AskPrice', 'BidPrice', 'BuySettle', 'CouponFreqCode', 'CouponFreqID', 'CouponRate', 'IDCurrency',
'LastCoupon', 'MaturityDate', 'MinimumBuyUnit', 'MultipleOfUnit', 'NextCoupon', 'Penerbit',
'ProductCode', 'ProductName', 'ProductAlias', 'RiskProfile', 'SellSettle'
],
$bond_datas
);
if ($insert_data) {
// make response as JSON File and store the file
$ods->makeJsonFile($bond_datas, 'feeds/bonds', 'bond.json');
}
}
// Mutual Fund data store to internal
if ($MFProductInqList !== null) {
$mf_datas = [];
foreach ($MFProductInqList as $row => $content) {
$mf_datas[] = [
'ProductCode' => $content->ProductCode,
'ProductName' => $content->ProductName,
'ProductCategory' => $content->ProductCategory,
'ProductType' => $content->ProductType,
'Currency' => $content->Currency,
'Performance1' => $content->field_1_tahun_mf,
'Performance2' => $content->Performance2,
'Performance3' => $content->Performance3,
'Performance4' => $content->Performance4,
'Performance5' => $content->Performance5,
'UrlProspektus' => $content->UrlProspektus,
'UrlFactSheet' => $content->UrlFactSheet,
'UrlProductFeatureDocument' => $content->UrlProductFeatureDocument,
'RiskProfile' => $content->RiskProfile,
'FundHouseName' => $content->FundHouseName,
'NAVDate' => $content->NAVDate,
'NAVValue' => $content->NAVValue
];
}
$insert_data_mf = $ods->setData(
'mutual_fund',
[
'ProductCode', 'ProductName', 'ProductCategory', 'ProductType', 'Currency', 'Performance1', 'Performance2', 'Performance3',
'Performance4', 'Performance5', 'UrlProspektus', 'UrlFactSheet', 'UrlProductFeatureDocument', 'RiskProfile', 'FundHouseName',
'NAVDate', 'NAVValue'
],
$mf_datas
);
if ($insert_data_mf) {
// make response as JSON File and store the file
$ods->makeJsonFile($mf_datas, 'feeds/mf', 'mutual_fund.json');
}
}
// console log
\Drupal::logger('ods')->notice($message);
}
So can I store the data to pristine drupal 8 table?
First, you need to create the content type in the Drupal 8 backend going to Structure > Content type.
Second you can add a node programmatically like this
use Drupal\node\Entity\Node;
$node = Node::create(array(
'type' => 'your_content_type',
'title' => 'your title',
'langcode' => 'en',
'uid' => '1',
'status' => 1,
'body'=> 'your body',
));
$node->save();

Laravel transactions with logic

I try to have logic in my transaction, but it just keeps adding the data to the database and I don't know what's going wrong...
The code I currently have:
public function addQuote($customer_id, Request $request)
{
//try catch, since there can be errors in it
DB::transaction(function() use ($customer_id, $request) {
try {
// Make a project for a quote, but not a main project, to not interfere with other existing projects
$quote_project = QuoteProject::create([
'projectnumber' => $request->project_number,
'name' => $request->project_name,
'address' => $request->project_address,
'zipcode' => $request->project_zipcode,
'city' => $request->project_city,
'country' => $request->project_country ?? 'BE',
'customer_id' => $customer_id,
]);
// Make a quote
$quote = Quote::create([
'status_id' => 1, // assign pending status
'reference' => $request->reference,
'number' => rand(),
'department_id' => $request->department,
'project_id' => $quote_project->id, // Created project id
'location_id' => ($request->location === 0) ? null : $request->location, // location -> can be 0 as value, if so, leave empty
'customer_id' => $customer_id,
'contact_id' => $request->contact_id,
'layout_id' => $request->layout_id,
'seller_id' => $request->seller_id,
'date_from' => Carbon::createFromFormat('d/m/Y', $request->date_from)->format('Y-m-d'),
'date_till' => Carbon::createFromFormat('d/m/Y', $request->date_till)->format('Y-m-d'),
'document_number' => $request->document_number,
'customer_number' => $request->customer_number,
'vat_type_id' => $request->vat_type_id,
'vat_tariff_id' => $request->vat_tariff_id,
]);
$quote->conditions()->attach($request->payment_conditions);
if (isset($request->head_group)) {
// set a global sync data variable
$sync_data = [];
// Loop over all the head groups
foreach ($request->head_group as $key => $head_group) {
// create or update head group
$created_head_group = ArticleGroup::updateOrCreate([
'quote_id' => $quote->id,
'name' => $head_group ?? ''
], [
'comment' => $request->head_group_comment[$key] ?? '',
'head_group' => 1,
'parent_group' => null,
'bold' => filter_var($request->bold_head[$key], FILTER_VALIDATE_BOOLEAN) ?? false,
'italic' => filter_var($request->italic_head[$key], FILTER_VALIDATE_BOOLEAN) ?? false,
'underline' => filter_var($request->underline_head[$key], FILTER_VALIDATE_BOOLEAN) ?? false,
'color' => str_replace('#', '', $request->color_head[$key]) ?? null
]);
// Loop over the sub groups in a main group
foreach ($request->sub_group[$key] as $s_key => $sub_group) {
// Create or update a subgroup
$created_sub_group = ArticleGroup::updateOrCreate([
'quote_id' => $quote->id,
'name' => $sub_group ?? ''
], [
'comment' => $request->sub_group_comment[$key][$s_key] ?? '',
'head_group' => 0,
'parent_group' => $created_head_group->id,
'bold' => filter_var($request->bold_sub[$key][$s_key], FILTER_VALIDATE_BOOLEAN) ?? false,
'italic' => filter_var($request->italic_sub[$key][$s_key], FILTER_VALIDATE_BOOLEAN) ?? false,
'underline' => filter_var($request->underline_sub[$key][$s_key], FILTER_VALIDATE_BOOLEAN) ?? false,
'color' => str_replace('#', '', $request->color_sub[$key][$s_key]) ?? null
]);
// Loop over the articles in the subgroup
foreach ($request->articles[$key][$s_key] as $a_key => $article_id) {
if (isset($request->articles[$key][$s_key])) {
$id = explode('-', $article_id);
$sync_data[$id[0]] = [
'name' => $request->custom_article_name[$key][$s_key][$a_key],
'quantity' => $request->quantity[$key][$s_key][$a_key],
'thickness' => $request->thickness[$key][$s_key][$a_key],
'price' => $request->article_price[$key][$s_key][$a_key],
'description' => $request->description[$key][$s_key][$a_key],
'group_id' => $created_sub_group->id
];
}
}
}
}
$quote->articles()->sync($sync_data); // sync the articles
}
// return data for ajax call, since the wizard works via an ajax call submit
return url('customers/' . $customer_id . '/quotations/');
} catch (\Exception $ex) {
return response()->json(['error' => $ex->getMessage()], 500);
}
}
);
}
If someone could explain me what I'm doing wrong here, that would be a really great help!
This is how it works. If inside DB::transaction exception is thrown then transaction is rolled back automatically. However in your implementation exception is not thrown because you catch it inside transaction and just try to return error response (what by the way won't work because you miss return in DB::transaction(function() use ($customer_id, $request) { line).
The easiest way to solve is to catch exception not inside DB::transaction but outside of it - then it will behave as you expected, transaction will be rolled back.
Alternative solution in some cases it not using DB::transaction but instead using manual:
DB::beginTransaction();
DB::rollBack();
DB::commit();
as described in documentation.

How to pass xsi type of parameter in PHP SoapClient

I am trying to consume soapclient based API of https://developer.signicat.com/documentation/signing/get-started-with-signing/full-flow-example/
There are tow methods of it
1- you have to upload a document and it returns you an SDS ID, this part works fine
2- then you need to use this SDS ID in second part of API to create a sign request method name is createRequest(),
This is where I am getting problem, I have passed all the parameters but still getting an error on one parameter which is xsi:type I am not sure how to pass this parameter from php array.
Here is the sample XML
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ref-sds-id="090520195vbxk9uuw4dks9tjm2pmpy7sx3na397xz6qclxtepaslnb00q7" send-to-archive="false" xsi:type="sds-document">
<sign-text-entry/>
<description>Loan contract.pdf</description>
</document>
here xsi:type="sds-document" this part is causing the issue
My Code:
$url = 'https://preprod.signicat.com/ws/documentservice-v3?wsdl';
$soap_setting = array(
"trace" => 1,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS + SOAP_USE_XSI_ARRAY_TYPE
);
$client = new SoapClient($url,$soap_setting);
$subject_type = $client->__getTypes();
$functions = $client->__getFunctions();
$subject = array(
'national-id'=> '198003010306',
'first-name' => 'Oskar',
'last-name' => 'Johansson',
'email' => 'kamran#creativerays.com'
);
$notification = array(
'recipient' => 'http://localhost/sign/php/',
'type' => 'URL',
'message' => 'Please seign ${taskUrl}',
'header'=> 'Test',
'notification-id' => '001'
);
$sdsdocument = array(
'ref-sds-id' => '100520193oz5vev0onyueul43ury4vz8g1hsnhr7w69pcwnoan96ojbtbb',
'send-to-archive' => true,
'description'=> 'test',
'sign-text-entry'=> 'test',
'xsi:type' => 'sds-document'
);
$documentaction = array(
'document'=> $sdsdocument,
'type'=> 'sign',
'optional'=> true,
'send-result-to-archive'=> true
);
$tasks = array(
'subject'=> $subject,
'document-action'=> $documentaction,
'notification'=> $notification,
'on-task-postpone'=> 'http://localhost/sign/php/?requestId=${requestId}&taskId=${taskId}&status=taskpostponed',
'on-task-complete'=> 'http://localhost/sign/php/?requestId=${requestId}&taskId=${taskId}&status=taskcomplete',
'on-task-cancel'=> 'http://localhost/sign/php/?requestId=${requestId}&taskId=${taskId}&status=taskcancelled',
'configuration'=> 'default',
'signature' =>array('method'=>'nbid-sign'),
'id'=> 'task00001',
'bundle'=> False
);
$request = array(
'language'=> 'en',
'task'=> $tasks
);
$tparam = array(
'service'=>'demo',
'password'=>'Bond007',
'request' =>$request
);
$create = $client->createRequest($tparam);
echo '<pre>';
print_r($create);
echo $client->__getLastRequestHeaders();
echo '</pre>';
The Error I am getting:
Fatal error: Uncaught SoapFault exception: [soap:Client] Failed to register new document action request: Document with id null must have subtype archive-document, sds-document, result-document, upload-document or provided-document

Categories