How to add a shipment (tracking code + change status to shipped) programmatically? - shopware6

I want to mark an order as shipped and add the tracking code inside a Shopware 6 CLI command.
I understand that I have to create a delivery and attach the tracking code. I could do this via DAL. But I am wondering if there is a higher-level service for this?
Do I have to use the state machine to change the status ? Or can this done in one step?
I have already written a test to check the tracking code:
$this->assertEquals('01234567890123', $order->get('deliveries')[0]->get('tracking_codes')[0]);
I think I can use the logic from \Shopware\Core\Checkout\Order\Api\OrderActionController::orderDeliveryStateTransition but it would require copy & paste.
EDIT For the tracking code I tried this:
// FIXME: get the right context
$context = Context::createDefaultContext();
$order = $this->findOrder($orderNumber);
/** #var \Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryCollection $deliveries */
$deliveries = $order->get('deliveries');
if (count($deliveries) == 0) {
throw new \LogicException('No delivery found');
}
if (count($deliveries) > 1) {
throw new \LogicException('We support only 1 delivery per order');
}
$deliveries->first()->setTrackingCodes([$trackingCode]);
$this->orderRepository->update([
[
'id' => $order->getId(),
'deliveries' => json_decode( json_encode($deliveries), true)
]
], $context);
But I get:
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/0/deliveries/0/shippingOrderAddress/salutation/translations/2fbb5fe2e29a4d70aa5854ce7ce3e20b/displayName] Dieser Wert sollte nicht leer sein.
1. [/0/deliveries/0/shippingOrderAddress/salutation/translations/2fbb5fe2e29a4d70aa5854ce7ce3e20b/letterName] Dieser Wert sollte nicht leer sein.
1. [/] Expected data to be array.
I also tried
$this->orderRepository->update([
[
'id' => $order->getId(),
'deliveries' => [
$deliveries->first()->getId() => [
'trackingCodes' => [ $trackingCode ]
]
]
]
], $context);
Which makes more sense to my, as I just want to update the tracking code, not the full shipment.
This throws:
Shopware\Core\Framework\DataAbstractionLayer\Write\WriteException : There are 5 error(s) while writing data.
1. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingOrderAddressId] Dieser Wert sollte nicht leer sein.
2. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingMethodId] Dieser Wert sollte nicht leer sein.
3. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/stateId] Dieser Wert sollte nicht leer sein.
4. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingDateEarliest] Dieser Wert sollte nicht null sein.
5. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingDateLatest] Dieser Wert sollte nicht null sein.

here is how i set an order shipped and complete
use Shopware\Core\System\StateMachine\Aggregation\StateMachineTransition\StateMachineTransitionActions;
use Shopware\Core\System\StateMachine\StateMachineRegistry;
use Shopware\Core\System\StateMachine\Transition;
private function setOrderComplete(OrderEntity $order, Context $context): void
{
$this->stateMachineRegistry->transition(new Transition(
OrderDefinition::ENTITY_NAME,
$order->getId(),
StateMachineTransitionActions::ACTION_COMPLETE,
'stateId'
), $context);
}
private function setDeliveryShipped(OrderDeliveryEntity $delivery, Context $context): void
{
$this->stateMachineRegistry->transition(new Transition(
OrderDeliveryDefinition::ENTITY_NAME,
$delivery->getId(),
StateMachineTransitionActions::ACTION_SHIP,
'stateId'
), $context);
}

For the tracking code, this works:
$this->deliveryRepository->update([
[
'id' => $deliveries->first()->getId(),
'trackingCodes' => [$trackingCode]
]
], $context);
And the full code - state transitions on order might also needed to be run, depending on the requirements:
$context = Context::createDefaultContext();
$order = $this->findOrder($orderNumber);
/** #var \Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryCollection $deliveries */
$deliveries = $order->get('deliveries');
if (count($deliveries) == 0) {
throw new \LogicException('No delivery found');
}
if (count($deliveries) > 1) {
throw new \LogicException('We support only 1 delivery per order');
}
$this->orderService->orderStateTransition(
$order->getId(),
'process',
new ParameterBag(),
$context
);
$deliveryId = $deliveries->first()->getId();
$this->deliveryRepository->update([
[
'id' => $deliveryId,
'trackingCodes' => [$trackingCode]
]
], $context);
$context->addExtension(
MailSendSubscriber::MAIL_CONFIG_EXTENSION,
new MailSendSubscriberConfig(false)
);
$this->orderService->orderDeliveryStateTransition(
$deliveryId,
'ship',
new ParameterBag(),
$context
);
$this->orderService->orderStateTransition(
$order->getId(),
'complete',
new ParameterBag(),
$context
);
}

Related

SMAX API - Failed to create Incident

I want to create an Incident in Service Management Automation(Microfocus - SMAX) using API.
I use activity HTTP Request. My properties are as follow:
Accepted Format: JSON
Request Method : POST
Request URL: “https://smax.mycompany.com/rest/9966332211/ems/bulk”
Cookies = LWSSO_COOKIE_KEY=Token
Body:
{
‘entities’: [
{
‘entity_type’: ‘Incident’,
‘properties’: {
‘ContactPerson’: ‘’,
‘ImpactScope’: ‘Enterprise’,
‘IncidentToCompany’: ‘14728’,
‘Urgency’: ‘TotalLossOfService’,
‘DisplayLabel’: ‘Non reception du mail de volumetrie d’appel’,
‘CurrentAssignment’: ‘ServiceDesk’,
‘ServiceDeskGroup’: ‘14546’,
‘ExpertGroup’: ‘14533’,
‘RegisteredForActualService’: ‘15393’,
‘Description’: ‘This is a test Incident. Please ignore it.’
}
}
],
‘operation’: ‘CREATE’
}
I Get the following error as reposnone:
“errorDetails”: {
“httpStatus”: 500,
“message”: “Failed to evaluate DSL expression ${current_update.RegisteredForActualService.IsChanged && entity.RegisteredForActualService.SupportLevel1Group != null && entity.ServiceDeskGroup == null}”,
“developer_message”: “”,
“message_key”: “failed_to_evaluate_dsl_expression”,
“message_rb”: “locale/workflow_errors”,
“message_arguments”: [
“${current_update.RegisteredForActualService.IsChanged && entity.RegisteredForActualService.SupportLevel1Group != null && entity.ServiceDeskGroup == null}”
],
“exceptionType”: “WorkflowException”
}
Do you know what might cause the error?
Kind regards

Issue with json datasource and datatables

I am trying to use a json retrieved from an external API and saved as a variable.
I keep getting the error:
DataTables warning: table id=pageTable - Requested unknown parameter '0' for row 0, column 0. For more information about this error, please see http://datatables.net/tn/4
I am initializing the table after the table is built and I have 4 columns both in the head and in the body.
The paging works but the table itself comes out empty.
What am I missing?
function build_table(feed_items){
console.log(feed_items)
var list = "";
for(i=0; i< feed_items.length; i++){
list += '<tr class="text-center">';
list += '<td>'+feed_items[i]["ns2:feedDate"]+'</td>';
list += '<td>'+feed_items[i]["ns2:feedStatus"]+'</td>';
list += '<td>'+feed_items[i]["ns2:feedType"]+'</td>';
list += '<td>'+feed_items[i]["ns2:itemsReceived"]+'</td>';
list += '</tr>';
}
$("tbody").html(list);
$('#pageTable').DataTable({
"pageLength": 10,
data: feed_items,
columns: [
{title: "ns2:feedDate"},
{title: "ns2:feedStatus"},
{title: "ns2:feedType"},
{title: "ns2:itemsReceived"}
],
stateSave: true,
dom: 'lBfrtip',
buttons: [
'excelHtml5',
'csvHtml5',
'pdfHtml5'
]
})
}

Regarding Bigquery datasetId and tableId

How do I get the datasetId and tableId from BigQuery. I tried to click the dropdown on the sidebar and copied the dataset info and table info, Is there any way, I can query the datasetId and tableId? but I got this error. I am using php client libraries to pull the BigQuery data.
How do I get the datasetId and tableId from BigQuery. I tried to click the dropdown on the sidebar and copied the dataset info and table info, Is there any way, I can query the datasetId and tableId? but I got this error. I am using php client libraries to pull the BigQuery data.
use Google\Cloud\BigQuery\BigQueryClient;
/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $datasetId = 'The BigQuery dataset ID';
// $tableId = 'The BigQuery table ID';
// $maxResults = 10;
$maxResults = 10;
$startIndex = 0;
$options = [
'maxResults' => $maxResults,
'startIndex' => $startIndex
];
$bigQuery = new BigQueryClient([
'projectId' => $projectId,
]);
$dataset = $bigQuery->dataset($datasetId);
$table = $dataset->table($tableId);
$numRows = 0;
foreach ($table->rows($options) as $row) {
print('---');
foreach ($row as $column => $value) {
printf('%s: %s' . PHP_EOL, $column, $value);
}
$numRows++;
}
I am getting this error.
Google\Cloud\Core\Exception\BadRequestException : {
"error": {
"code": 400,
"message": "Invalid dataset ID \"mc-data-2:Turnflex\". Dataset IDs must be alphanumeric (plus underscores and dashes) and must be at most 1024 characters long.",
"errors": [
{
"message": "Invalid dataset ID \"mc-data-2:Turnflex\". Dataset IDs must be alphanumeric (plus underscores and dashes) and must be at most 1024 characters long.",
"domain": "global",
"reason": "invalid"
}
],
"status": "INVALID_ARGUMENT"
}
}
According to PHP Google Cloud client library documentation for a proper BigQueryClient() class initialization you might be requiring propagate $projectId variable. In case of any Biqguery data querying or discovering action aimed, you would probably leverage query() method submitting Bigquery Job with the particular custom query or explicitly define dataset() and table() as the target Bigquery location.
Confirming #Priya Agarwal presumption, I've checked the code snippet from your example and it works as intended. I've catched the similar error that you've reported, once I made connection with $datasetId variable exposed jointly with tableId:
$datasetId = 'datasetId:tableId'
instead of:
$datasetId = 'datasetId'

How to turn string output from sql to integer?

I am generating charts using google chart api. I have done it locally and successfully produce the charts. However, when I transfer them to server (cpanel) the charts is ruined. I have detected that the output of sql query for generating the charts value is produced in string format with "6".
This is the code to get the charts' value:
public function gender()
{
$data = DB::table('results')
->select(
DB::raw('gender as gender'),
DB::raw('count(*) as number'))
->groupBy('gender')
->get();
//dd($data);
$array[] = ['Gender', 'Number'];
foreach($data as $key => $value)
{
$array[++$key] = [$value->gender, $value->number];
}
//dd($array);
return view('gender')->with('gender', json_encode($array));
}
In my local, I try to access the data of the sql using dd($data); producing:
Collection {#263 ▼
#items: array:2 [▼
0 => {#264 ▼
+"gender": "female"
+"number": 6
}
1 => {#266 ▼
+"gender": "male"
+"number": 6
}
]
}
I tried accessing in server using same dd($data);
Collection {#260 ▼
#items: array:2 [▼
0 => {#261 ▼
+"gender": "female"
+"number": "6"
}
1 => {#263 ▼
+"gender": "male"
+"number": "6"
}
]
The difference is the number value from server code is in string.
Why this happened and how to fix the problem?
I had a similar issue. It seems it's a PHP issue. Are you running the same PHP versions on local and production?
In any case, you could also explicitly cast it as an UNSIGNED integer. I was able to do that with the following:
$data = DB::table('results')
->selectRaw('gender as gender, CAST(count(*) AS UNSIGNED) as number')
->groupBy('gender')
->get();

Field not required but if user entered a value it must be meeting some rules (vuetify rules)

I am trying to enter a validation for a field that accept url, the field not required but if user entered a value it must meet url regex.
so I tried the following code
<v-text-field height="34px" v-model="website" single-line outline placeholder="http://" :rules="urlRules"></v-text-field>
this attribute :rules="urlRules" refer to a bulk of rules that I give in my vue object
urlRules: [
v => !!v || 'required',
v => /[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi.test(v) || 'Please enter a correct URL to your website'
],
I want to change the validation in the rule object to make it not required but if user entered a url it must be correct
This is how I manage to validate non required fields with Vuetify:
urlRules: [
(v) => ( !v || YOUR_REGEX.test(v) ) || 'Please enter a correct URL to your website'
],
Check the !v. I am validating first, that if nothing is passed, will trigger a true value, this means, will not be required. But if something is passed, will check your regex or whatever expression you want to place.
There are other options, like an if else inside the rules, but i prefer this (prettier).
You can do it like below
urlRules: [
v => (v && v.length > 0 && !YOUR_REGEXP.test(v)) ? 'Please enter a correct URL to your website' : true
],
I solved this by maintaining separate validation functions as follows:
export const emailFormat = v =>
/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v) ||
"E-mail must be valid";
export const emptyEmailFormat = v => {
if (v && v.length > 0) {
return /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v) ||
"E-mail must be valid";
} else {
return true
}
}
emailRules = {
isRequired: this.question.mandatory ? required : true,
emailFormat: this.question.mandatory ? emailFormat : emptyEmailFormat
};
I got this idea after posting this question
I used a regex that accept an empty value with the pattern I want
here is what I used
urlRules: [
v => /^$|[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi.test(v) || 'Please enter a correct URL to your website'
],
so if there is a better answer share it with me plz