0% found this document useful (0 votes)
4 views18 pages

Objetivo

Uploaded by

Richard Lozano
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views18 pages

Objetivo

Uploaded by

Richard Lozano
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 18

Destinos mas descriptivos para move - Agregar Seller Name

Objetivo:
Agregar el nombre de la cuenta del seller a los nombres de origenes al crear objetos en move y
mandarlo como destino

Detalle:
● Al crear un shipment o workflow en move, para la dirección de origen debe anteponerse
el nombre de la cuenta, ej. "Hoga - Deposito principal" en vez de "Deposito principal".
● Tener en cuenta lo siguiente:
○ Trimear espacios y signos de puntuación o no alfanuméricos
○ No repetir el nombre de la cuenta en el origen.
■ Ej. Cuenta = "Hoga" y Origen = "Hoga" -> enviar "Hoga"
■ Ej. Cuenta = "Beiró Hogar" y Origen = "Depósito Beiró Hogar" -> enviar
"Beiró Hogar - Depósito"
○ Si el nombre de la cuenta es mas largo que 15 caracteres, recortarlo.
■ Ej. Cuenta = "Visuar, Vstore, Samsung, Smartlife, Mercadolibre" y Origen
"VISUAR (Parque Industrial Cañuelas)" -> enviar "Visuar Vstore -
VISUAR Parque Industrial Cañuelas"

app/Services/Api/ZippinMove.php
<?php
/*
* Copyright (c) 2023-2024. Zippin Logistics International, Inc. and its
subsidiaries.
* Proprietary and confidential. No reproduction or derivative work is
allowed from this code.
*/

namespace Kraken\Services\Api;

use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use Kraken\Events\Shipment\MoveWorkflowUpdatedEvent;
use Kraken\Models\RecollectionBag;
use Kraken\Models\Shipment;
use Kraken\Models\Shipment\MoveWorkflow;
use Kraken\Services\Api\ZippinMove\WorkflowBuilder;
use Kraken\Services\Carriers\SelfServiceCarrier;
use Kraken\Services\Helpers;
use Kraken\Support\ActionResult;

class ZippinMove
{
protected string $org;

protected string $shipper_id;

protected string $token;

public function __construct($org, $shipper_id, $token)


{
$this->org = $org;
$this->shipper_id = $shipper_id;
$this->token = $token;
}

public static function forCarrier($carrier): ZippinMove|bool


{
$move_settings = $carrier?->move_settings;

if (! isset($move_settings['credentials']['carrier']) || !
isset($move_settings['credentials']['token'])) {
return false;

} else {

return new ZippinMove(


$move_settings['credentials']['carrier'],
$move_settings['credentials']['shipper_id'],
$move_settings['credentials']['token'],
);
}

}
public function createShipment(Shipment $shipment, $withInitialWorkflow
= true)
{
$body = [
'shipper_id' => $this->shipper_id,
'external_reference' => $shipment->remito,
'declared_value' => $shipment->carrier_declared_value,
'origin' => [
'name' => $shipment->origin->name,
'street' => $shipment->origin->street,
'street_number' => $shipment->origin->street_number,
'floor' => null,
'apartment' => null,
'reference' => $shipment->origin->street_extras,
'city' => $shipment->origin->city->name,
'state' => $shipment->origin->state->name,
'country' => $shipment->origin->country->iso_code,
'zipcode' => $shipment->origin->zipcode,
'phone' => str_pad($shipment->origin->phone, 10, '1',
STR_PAD_LEFT),
'email' => $shipment->origin->email,
'geo_latitude' => $shipment->origin->location_latitude,
'geo_longitude' => $shipment->origin->location_longitude,
],
'requires_pickup' => false,
'destination' => [
'name' => $shipment->destination->name,
'street' => $shipment->destination->street,
'street_number' => $shipment->destination->street_number,
'floor' => null,
'apartment' => null,
'reference' => $shipment->destination->street_extras,
'city' => $shipment->destination->city->name,
'state' => $shipment->destination->state->name,
'country' => $shipment->destination->country->iso_code,
'zipcode' => $shipment->destination->zipcode,
'phone' => $shipment->destination->phone,
'email' => $shipment->destination->email,
'geo_latitude' => $shipment->destination-
>location_latitude,
'geo_longitude' => $shipment->destination-
>location_longitude,
],
'packages' => [],
];

if (! $withInitialWorkflow) {
$body['initial_workflow'] = false;
}

if (empty($body['origin']['email'])) {
$body['origin']['email'] = $shipment->account->operations_email
?? $shipment->account->communication_email;
}

if (empty($body['origin']['phone'])) {
$body['origin']['phone'] = $shipment->account->operations_phone
?? $shipment->account->company_phone;
}

if (empty($body['destination']['street_number'])) {
$body['destination']['street_number'] = 'S/N';
}

$i = 1;
foreach ($shipment->packages as $package) {
if ($shipment->carrier->code == SelfServiceCarrier::CODE) {
$label_code = $package->id;
} else {
$label_code = $shipment->remito.'-'.str_pad($i, 4, '0',
STR_PAD_LEFT);
}
$body['packages'][] = [
'external_reference' => $shipment->external_id.'-'.$i,
'label_code' => (string) $label_code,
'classification' => 'default',
'grams' => $package->weight,
'length' => $package->length,
'width' => $package->width,
'height' => $package->height,
];
$i++;
}

$url = 'https://'.$this->org.'.zippinmove.com/api/v1/shipments';
$response = Http::withToken($this->token)->asJson()->post($url,
$body);

if ($response->json('success')) {
return ActionResult::success('Shipment created', ['response' =>
$response->json()]);
}

return ActionResult::failure($response->reason(), ['response' =>


$response->json(), 'body' => $body]);
}

public function cancelShipment($shipment_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/shipments/'.
$shipment_id.'/cancel';

$response = Http::withToken($this->token)->asJson()->post($url,
null);

if ($response->json('success')) {
return ActionResult::success('Shipment canceled', ['response'
=> $response->json()]);
}

return ActionResult::failure($response->reason(), ['response' =>


$response->json()]);

public function createWorkflow($workflow_code, Shipment $shipment,


array $metadata = [])
{
$workflowBuilder = new WorkflowBuilder($workflow_code);
$body = $workflowBuilder
->forShipment($shipment)
->withAutomaticSettings()
->getData();

$url = 'https://'.$this->org.'.zippinmove.com/api/v1/workflows';
$response = Http::withToken($this->token)->asJson()->post($url,
$body);

if ($response->json('success')) {
Shipment\MoveWorkflow::create([
'shipment_id' => $shipment->id,
'workflow_id' => $response->json('workflow.id'),
'workflow_type' => $workflow_code,
'workflow_status' => $response-
>json('workflow.current_status', 'new'),
'move_workflows_metadata' => empty($metadata) ? null :
$metadata,
]);

return ActionResult::success('Workflow created', ['response' =>


$response->json()]);
}

return ActionResult::failure($response->reason(), ['response' =>


$response->json(), 'body' => $body]);

public function getWorkflow($workflow_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/workflows/'.
$workflow_id;
$response = Http::withToken($this->token)->get($url);

if ($response->json('id')) {
return $response->json();
}

Helpers::getLog('api.zippinmove')->warning('Unable to get workflow


'.$workflow_id, ['response' => $response->json()]);
return false;
}

public function updateWorkflowFromWebhook($webhook_data)


{
if (Arr::get($webhook_data, 'resource.type') != 'workflow') {
return ActionResult::failure('Not a workflow');
}

$workflow_id = Arr::get($webhook_data, 'resource.id');


$workflow = Shipment\MoveWorkflow::where('workflow_id',
$workflow_id)->first();
if ($workflow && $new_status = Arr::get($webhook_data,
'metadata.new_status')) {
$workflow->workflow_status = $new_status;
$workflow->workflow_status_updated_at = now();
$workflow->save();
Helpers::getLog('api.zippinmove')->info('Workflow status
updated from webhook', ['workflow_id' => $workflow_id, 'new_status' =>
$new_status, 'shipment_id' => $workflow->shipment_id]);
event(new MoveWorkflowUpdatedEvent($workflow->shipment_id,
$workflow_id, $workflow->workflow_type, $new_status,
Arr::get($webhook_data, 'metadata', [])));
}
}

public function cancelWorkflow(MoveWorkflow $shipment_workflow):


ActionResult
{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/workflows/'.
$shipment_workflow->workflow_id.'/cancel';
$response = Http::withToken($this->token)->asJson()->post($url);

if ($response->successful()) {
$shipment_workflow->workflow_status = $response-
>json('data.workflow.current_status');
$shipment_workflow->update();
return ActionResult::success('Workflow canceled', ['response'
=> $response->json()]);
}

return ActionResult::failure($response->reason(), ['response' =>


$response->json()]);
}

public function updateWorkflow($workflow_id, $body): ActionResult


{
$url = 'https://' . $this->org .
'.zippinmove.com/api/v1/workflows/' . $workflow_id;
$response = Http::withToken($this->token)->asJson()->put($url,
$body);
if ($response->successful()) {
return ActionResult::success('Workflow updated', ['response' =>
$response->json()]);
}

return ActionResult::failure($response->reason(), ['response' =>


$response->json()]);
}

public function getShipmentTracking($shipment_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/shipments/'.
$shipment_id.'/tracking';
$response = Http::withToken($this->token)->get($url);

if ($response->json('tracking')) {
return $response->json('tracking');
}

Helpers::getLog('api.zippinmove')->warning('Unable to get shipment


tracking: '.$shipment_id, ['response' => $response->json()]);

return false;
}

public function getShipmentAttachments($shipment_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/shipments/'.
$shipment_id.'/attachments';
$response = Http::withToken($this->token)->get($url);

if ($response->json('attachments')) {
return $response->json('attachments');
}

Helpers::getLog('api.zippinmove')->warning('Unable to get shipment


attachments: '.$shipment_id, ['response' => $response->json()]);

return false;
}

public function getShipmentAttachment($shipment_id, $attachment_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/shipments/'.
$shipment_id.'/attachments/'.$attachment_id;
$response = Http::withToken($this->token)->get($url);

if ($response->json('content')) {
return $response->json();
}

Helpers::getLog('api.zippinmove')->warning('Unable to get shipment


attachment: '.$shipment_id.' - '.$attachment_id, ['response' => $response-
>json()]);

return false;
}

public function getRoutes()


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/routes';
$response = Http::withToken($this->token)->get($url);
if ($response->json('routes')) {
return $response->json();
}
Helpers::getLog('api.zippinmove')->warning('Unable to get routes',
['response' => $response->json()]);

return false;

public function getRoute($route_id)


{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/routes/'.
$route_id;
$response = Http::withToken($this->token)->get($url);
if ($response->json('id')) {
return $response->json();
}

Helpers::getLog('api.zippinmove')->warning('Unable to get route',


['route_id' => $route_id, 'response' => $response->json()]);

return false;

public function getTask($task_id, $withHistory = false,


$withAttachments = false)
{
$url = 'https://'.$this->org.'.zippinmove.com/api/v1/tasks/'.
$task_id;
$query = [];

if ($withAttachments) {
$query['include_attachments'] = 1;
}

if ($withHistory) {
$query['include_history'] = 1;
}

$response = Http::withToken($this->token)->get($url, $query);


if ($response->json('id')) {
return $response->json();
}

Helpers::getLog('api.zippinmove')->warning('Unable to get task',


['task_id' => $task_id, 'response' => $response->json()]);

return false;

public static function createRecollectionBagWorkflows(RecollectionBag


$closedBag, $check_existing_workflow = true)
{
$log = Helpers::getLog('api.zippinmove');
$move_settings = $closedBag->crossdock?->carrier?->move_settings;

if (! isset($move_settings['credentials']['carrier']) || !
isset($move_settings['credentials']['token'])) {
$log->error('Credenciales de ZippinMove incompletas', ['bag_id'
=> $closedBag->id, 'move_settings' => $move_settings, 'crossdock_carrier'
=> $closedBag->crossdock?->carrier?->id]);

return ActionResult::failure('Credenciales de ZippinMove


incompletas');

} else {

$move = new ZippinMove(


$move_settings['credentials']['carrier'],
$move_settings['credentials']['shipper_id'],
$move_settings['credentials']['token'],
);

$shipment_workflows = ['created' => [], 'skipped' => [],


'failed' => []];

foreach ($closedBag->shipments as $shipment) {

if ($check_existing_workflow) {
// Check if shipment has another workflow
if (Shipment\MoveWorkflow::where('shipment_id',
$shipment->id)->where(
'workflow_type', ZippinMove\
WorkflowBuilder::BLUEPRINT_SELLER_TO_CROSSDOCK
)->where('move_workflows_metadata->bag_id', $closedBag-
>id)->count()) {
$log->warning('Shipment ya tiene workflow seller-
to-xd en ZippinMove', ['bag_id' => $closedBag->id, 'shipment_id' =>
$shipment->id]);
$shipment_workflows['skipped'][] = $shipment->id;

continue;
}
}

$metadata = [
'bag_id' => $closedBag->id,
];

try {
$creation = $move->createWorkflow(ZippinMove\
WorkflowBuilder::BLUEPRINT_SELLER_TO_CROSSDOCK, $shipment, $metadata);

if ($creation->wasSuccessful()) {
$log->info('Workflow creado en ZippinMove',
['bag_id' => $closedBag->id, 'shipment_id' => $shipment->id, 'workflow_id'
=> $creation->getRelated('response')['workflow']['id']]);
$shipment_workflows['created'][$shipment->id] =
$creation->getRelated('response')['workflow']['id'];
} else {
$log->error('Error al crear workflow en ZippinMove:
'.$creation->getReason(), ['bag_id' => $closedBag->id, 'shipment_id' =>
$shipment->id, 'related' => $creation->getRelated()]);
$shipment_workflows['failed'][$shipment->id] =
$creation->getReason();
}
} catch (\Exception $e) {
$log->error('Error al crear workflow en ZippinMove: '.
$e->getMessage(), ['bag_id' => $closedBag->id, 'shipment_id' => $shipment-
>id, 'related' => $e]);
$shipment_workflows['failed'][$shipment->id] = $e-
>getMessage();
}
}

if (! count($shipment_workflows['created'])) {
return ActionResult::failure('No se crearon workflows');
} else {
return ActionResult::success('Workflows creados',
['shipment_workflows' => $shipment_workflows]);
}
}
}

public static function cancelRecollectionBagWorkflows(RecollectionBag


$closedBag): void
{
$log = Helpers::getLog('api.zippinmove');
$move_settings = $closedBag->crossdock?->carrier?->move_settings;

if (! isset($move_settings['credentials']['carrier']) || !
isset($move_settings['credentials']['token'])) {
$log->error('Credenciales de ZippinMove incompletas', ['bag_id'
=> $closedBag->id, 'move_settings' => $move_settings, 'crossdock_carrier'
=> $closedBag->crossdock?->carrier?->id]);

} else {

$move = new ZippinMove(


$move_settings['credentials']['carrier'],
$move_settings['credentials']['shipper_id'],
$move_settings['credentials']['token'],
);

$shipment_workflows = ['cancel' => []];

foreach ($closedBag->shipments as $shipment) {


$shipments_workflows = Shipment\
MoveWorkflow::where('shipment_id', $shipment->id)
->where('workflow_type', ZippinMove\
WorkflowBuilder::BLUEPRINT_SELLER_TO_CROSSDOCK)
->where('move_workflows_metadata->bag_id', '!=',
$closedBag->id)
->where('workflow_status', 'new')->get();

foreach ($shipments_workflows as $shipment_workflow) {


try {
$cancelResult = $move-
>cancelWorkflow($shipment_workflow);

if ($cancelResult->wasSuccessful()) {
$log->info('Workflow cancelado en ZippinMove',
['workflow_id' => $shipment_workflow->workflow_id, 'id' =>
$shipment_workflow->id]);
$shipment_workflows['cancel']
[$shipment_workflow->id] = $shipment_workflow->id;
} else {
$log->error('Error al cancelar workflow en
ZippinMove: '.$cancelResult->getReason(), ['workflow_id' =>
$shipment_workflow->workflow_id, 'id' => $shipment_workflow->id]);
}
} catch (\Exception $e) {
$log->error('Error al cancelar workflow en
ZippinMove: '.$e->getMessage(), ['workflow_id' => $shipment_workflow-
>workflow_id, 'id' => $shipment_workflow->id]);
}
}
}

if (! count($shipment_workflows['cancel'])) {
$log->info('No se cancelaron workflows');
} else {
$log->info('Workflows cancelados', ['shipment_workflows' =>
$shipment_workflows['cancel']]);
}
}
}

public static function updateRecollectionBag(RecollectionBag $bag):


void
{
$log = Helpers::getLog('api.zippinmove');
$move_settings = $bag->crossdock?->carrier?->move_settings;

if (! isset($move_settings['credentials']['carrier']) || !
isset($move_settings['credentials']['token'])) {
$log->error('Credenciales de ZippinMove incompletas', ['bag_id'
=> $bag->id, 'move_settings' => $move_settings, 'crossdock_carrier' =>
$bag->crossdock?->carrier?->id]);

} else {

$move = new ZippinMove(


$move_settings['credentials']['carrier'],
$move_settings['credentials']['shipper_id'],
$move_settings['credentials']['token'],
);

$updated_workflows = [];

foreach ($bag->shipments as $shipment) {


$shipment_workflows = $shipment->moveWorkflows()
->whereIn('workflow_type', [
ZippinMove\
WorkflowBuilder::BLUEPRINT_SELLER_TO_CROSSDOCK,
ZippinMove\
WorkflowBuilder::BLUEPRINT_POINT_TO_CROSSDOCK,
])
->where('move_workflows_metadata->bag_id', '!=', $bag-
>id)
->where('workflow_status', 'new')
->get();

if (! $shipment_workflows->count()) {
$log->warning('Shipment no tiene workflows seller-to-xd
o point-to-xd en ZippinMove', ['bag_id' => $bag->id, 'shipment_id' =>
$shipment->id]);
continue;
}

$body = [
'settings' => [
[
'step_name' => 'pickup',
'should_complete_after' => $shipment-
>recollectionBag->must_picked_at->midDay()-
>setTimezone(config('app.display_timezone'))->startOfDay()->utc()-
>format('Y-m-d H:i:s'),
'should_complete_before' => $shipment-
>recollectionBag->must_picked_at->midDay()-
>setTimezone(config('app.display_timezone'))->endOfDay()->utc()-
>format('Y-m-d H:i:s'),
],
[
'step_name' => 'deliver_to_crossdock',
'should_complete_after' => $shipment-
>recollectionBag->must_picked_at->midDay()-
>setTimezone(config('app.display_timezone'))->startOfDay()->utc()-
>format('Y-m-d H:i:s'),
'should_complete_before' => $shipment-
>recollectionBag->must_picked_at->midDay()-
>setTimezone(config('app.display_timezone'))->endOfDay()->utc()-
>format('Y-m-d H:i:s'),
],
]
];

foreach ($shipment_workflows as $shipment_workflow) {


try {
$updateResult = $move-
>updateWorkflow($shipment_workflow->workflow_id, $body);

if ($updateResult->wasSuccessful()) {
$log->info('Workflow actualizado en
ZippinMove', ['workflow_id' => $shipment_workflow->workflow_id, 'id' =>
$shipment_workflow->id]);
$updated_workflows[$shipment_workflow->id] =
$shipment_workflow->id;
} else {
$log->error('Error al actualizar workflow en
ZippinMove: '.$updateResult->getReason(), ['workflow_id' =>
$shipment_workflow->workflow_id, 'id' => $shipment_workflow->id]);
}
} catch (\Exception $e) {
$log->error('Error al actualizar workflow en
ZippinMove: '.$e->getMessage(), ['workflow_id' => $shipment_workflow-
>workflow_id, 'id' => $shipment_workflow->id]);
}
}
}

if (! count($updated_workflows)) {
$log->info('No se actualizaron workflows');
} else {
$log->info('Workflows actualizados', ['shipment_workflows'
=> $updated_workflows]);
}
}
}
}

app/Models/Shipment.php
public function origin()
{
return $this->hasOne(Address::class, 'id', 'origin_id');
}

app/Models/Address.php
public function address_book()
{
return $this->hasOne(AddressBook::class, 'id', 'address_book_id');
}

Comentarios:
cuando una adres tiene una relacion con adresbook
si el origin o destination tiene un adresbook asociado le concatena el nombre a delante
15:25
aacount_id del origen con el account_id del envio coincide

You might also like