GithubHelp home page GithubHelp logo

shiptown's Introduction

Management Products API

The Management Products API is a Laravel-based web application that allows users to manage products in a database.

Getting Started

To get started with the Management Products API, follow these steps:

  1. Clone the repository: git clone https://github.com/codingcab/ShipTown.git
  2. Navigate to the project directory: cd ShipTown
  3. Install dependencies: composer install
  4. Copy the .env.example file to .env: cp .env.example .env
  5. Generate a new application key: php artisan key:generate
  6. Create a new MySQL database for the application and update the .env file with your database credentials
  7. Run database migrations: php artisan migrate
  8. Start the application: php artisan serve

Authentication

The Management Products API uses token-based authentication to secure API endpoints. To authenticate, send a POST request to the /api/auth/login endpoint with your email and password in the request body. The API will return a JSON response containing your authentication token. To access authenticated endpoints, include your token in the Authorization header of your requests.

Error Handling

The Management Products API uses HTTP status codes to indicate the success or failure of requests. Successful requests will return a 200 OK status code, while unsuccessful requests will return an appropriate error code (e.g. 400 Bad Request, 401 Unauthorized, 404 Not Found, etc.). In addition, error messages will be included in the response body.

Contributing

Contributions to the Management Products API are welcome! To contribute, please follow these steps:

  1. Fork the repository.
  2. Create a new branch for your changes: git checkout -b my-new-branch
  3. Make your changes and commit them: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-branch
  5. Submit a pull request.

Please ensure that your code follows the existing coding style and includes tests for any new functionality.

License

The Management Products API is open source software licensed under the MIT license. Please see the LICENSE file for more details.

Contact Information

If you have any questions or issues with the Management Products API, please contact the project owner at [email protected].


Application - Core Principles

  • Core functionality it's Inventory Management of stock
  • Each product should have a unique SKU (products.sku)
  • Each product might have multiple barcodes (products_aliases)
  • We can have multiple locations (warehouses)
  • Each product can be in multiple locations (inventory)
  • Each inventory can have multiple reservations (inventory_reservations)
  • We import orders from multiple sources (orders)
  • Each order can have multiple products (orders_products)
  • We automatically group orders by order_status to help with the most efficient shipment and delivery process
  • We help with stock management, restocking, reordering, and stock taking

Use cases

Small Web Store / eCommerce Fulfillment Center

  1. User logs in
  2. User connects Magento2 API or other sources
  3. Orders are fetched from eCommerce Store or other sources
  4. Orders are grouped by order_status for most efficient shipment and delivery process
  5. Users pick and pack the products
  6. Courier labels are automatically printed and attached to the packages
  7. AutoPilot suggest the next best order to the user, based on the most efficient route
  8. Clients are notified of the shipment and tracking number

3rd Party eCommerce Fulfillment Center (3PL, 4PL, Multi-Channel, Multi-Location, Multi-User)

  1. User logs in
  2. User connects CLIENTS Magento2 API (multiple allowed)
  3. User connects Couriers API (multiple allowed)
  4. Orders are fetched from CLIENTS eCommerce Store
  5. Order Automations group orders by order_status for most efficient shipment and delivery process ensuring that standards required are met
  6. Order are picked in batches for efficiency
  7. AutoPilot suggest the next best order to the user, based on the most efficient route and request for packing
  8. Courier labels are automatically printed and attached to the packages
  9. Clients are notified of the shipment and tracking number

Retail Store

  1. User logs in
  2. User connects ePOS API
  3. Sales are fetched from ePOS
  4. Inventory can be managed by the user (goods in, goods out, stock take, stock checks, sales, damages...)
  5. AutoPilot suggest restock level and reorder points
  6. Store staff updates inventory restocking levels and reorder points to their needs
  7. Stock gets delivered based on the reorder points and restocking levels
  8. Stock is automatically requested from fulfillment center
  9. AutoPilot monitors the stock for possible stock issues and suggests actions to the user
  10. Buying department can see the sales and stock levels and make decisions based on the accurate data

Click and Collect orders (eCommerce and Retail Store)

  1. User logs in
  2. User connects eCommerce Store API
  3. Customer places an order requesting collection in specific location
  4. Orders are fetched from eCommerce Store
  5. Orders are Automatically dispatched to the specific location
  6. Orders Automations group orders by order_status for most efficient shipment and delivery process
  7. Users pick and pack the products
  8. Courier labels are automatically printed and attached to the packages
  9. AutoPilot suggest the next best order to the user, based on the most efficient route
  10. Clients are notified of the shipment and tracking number

Preorders (Layaway)

  1. User logs in
  2. User connects retail store ePOS API
  3. Orders are created and managed on the ePOS system
  4. Orders are marked for shipment on the ePOS system
  5. Orders are fetched from ePOS
  6. Orders are grouped by order_status for most efficient shipment and delivery process
  7. Users pick and pack the products
  8. Courier labels are automatically printed and attached to the packages
  9. AutoPilot suggest the next best order to the user, based on the most efficient route
  10. Clients are notified of the shipment and tracking number

Code Structure

Models (App\Models)

Models are used to interact with the database. They are used to read and write data to the database using eloquent

Observers (App\Observers)

Observers are used to listen for database record changes (Model) and dispatch events when they occur.

Example: OrderObserver listens for changes in the Order model and dispatches OrderUpdatedEvent when changes happen.

Events (App\Events)

Event are dispatched throughout the application to notify other parts of the application that something has happened and they should take action.

For example, when an order is created, an event is dispatched to notify the shipping department that they should take action.

Example: OrderUpdatedEvent is dispatched when an order is updated. InventoryReservations module listens for this event and takes action to ensure stock is not oversold.

Modules (App\Modules)

Modules are used to group related functionality together.

  • modules should listen to events and take action when they occur
  • modules should be ideally maintaining their own data
  • modules data tables should prefix with module_ and module name (e.g. modules_inventory_reservations_configuration)
  • deleting a module should not affect functionality of other parts of the application

Each module has its own folder and might contains the following:

  • ModuleServiceProvider (App\Modules\InventoryReservations\src\ModuleServiceProvider.php)
  • Controllers (App\Modules\InventoryReservations\src\Controllers)
  • Models (App\Modules\InventoryReservations\src\Models)
  • Observers (App\Modules\InventoryReservations\src\Observers)
  • Events (App\Modules\InventoryReservations\src\Events)
  • Listeners (App\Modules\InventoryReservations\src\Listeners)
  • Migrations (App\Modules\InventoryReservations\Database\src\Migrations)
  • Seeders (App\Modules\InventoryReservations\Database\src\Seeders)
  • Views (App\Modules\InventoryReservations\src\Views)
  • Resources (App\Modules\InventoryReservations\src\Resources)
  • Requests (App\Modules\InventoryReservations\src\Requests)

Module Configuration

Modules Service Providers are used to register the module with the application and to load the module configuration.

<?php

namespace App\Modules\Magento2MSI\src;

use App\Events\EveryFiveMinutesEvent;
use App\Events\Product\ProductTagAttachedEvent;
use App\Modules\BaseModuleServiceProvider;

class Magento2MsiServiceProvider extends BaseModuleServiceProvider
{
    public static string $module_name = 'eCommerce - Magento 2 MSI';

    public static string $module_description = 'Module provides connectivity to Magento 2 API - Multi Source Inventory';

    public static string $settings_link = '/settings/modules/magento2msi';

    public static bool $autoEnable = false;

    protected $listen = [
        EveryFiveMinutesEvent::class => [
            Listeners\EveryFiveMinutesEventListener::class
        ],

        ProductTagAttachedEvent::class => [
            Listeners\ProductTagAttachedEventListener::class,
        ],
    ];

    public static function enabling(): bool
    {
        // Add your logic here
        return parent::enabling();
    }
}

Module Installation

Modules are installed using migrations

<?php

use App\Modules\Magento2MSI\src\Magento2MsiServiceProvider;
use Illuminate\Database\Migrations\Migration;

return new class extends Migration
{
    public function up(): void
    {
        Magento2MsiServiceProvider::installModule();
    }
};

Tests (/Tests)- php artisan test

Helps us to make sure we didn't break anything accidentally

Dusk Tests (/Tests/Browser) - php artisan dusk

Dusk Tests sof what user would do, not what the code does

Route Tests (Tests/Feature)

Write simple but meaningful, easy to understand tests (e.g. test if api route response success if given some data)

Unit / Module Tests (Tests/Unit)

Write tests for each module to ensure it works as expected

Code Design Principles

  • User experience and efficiency is the important thing, this is the ultimate problem we are solving
  • Make the code clear and simple so we can understand it and maintain it for years

Scale

We design for the size of the database:

  • 20 locations (warehouses, stores, etc)
  • 30 users
  • 100 000 orders fulfilled per year
  • 500 000 products
  • 10 000 000 inventory records

Server size: 4 core, 16gb ram, 500gb ssd, 1gbps

shiptown's People

Contributors

arturhanusek avatar rizkypujiraharja avatar robgoodliffe avatar joseconsador avatar cmhayden avatar laravel-shift avatar dependabot[bot] avatar yan-afriyoko-coder avatar akbarmridho avatar rafnexx avatar codingcabproduction avatar daniyals14 avatar

Watchers

 avatar  avatar

shiptown's Issues

Refactor migrations_core_v1 file

Merge migrations into core_v1 migration (up to Jan 31 2024)

The idea is to have everything nice and clear, one Schema:create per table, see the samples:
#258
#260

The likes of Install module migrations should go to InstallApp script
https://github.com/codingcab/ShipTown/blob/dev/database/migrations/2023_08_25_195535_install__inventory_movements_module.php
https://github.com/codingcab/ShipTown/blob/dev/app/Console/Commands/InstallApp.php

For easier review, please do smaller commits, merge 2-3 migrations at at time and commit, I can easily check each one then.

Move /tests/Feature/Modules to /tests/Unit/Modules

this will require to update ModulesCoverageTest

there might be some test which should stay in /tests/Feature/Modules (routes tests) so the best way would be to update ModulesCoverageTest and then start moving the tests, one module at a time, checking if everything works ok

Make admin / settings web routes standarized

/routes/web.php

  • all routes should be as follows:
    /settings/*
    /settings/modules/*

  • intent to remove names from routes

  • change reference in navigation and other places from named routes to direct links

routes as below should be refactored:
admin/settings/*
admin/settings/modules/*
admin/modules/setting
etc etc

sample:
current: Route::view('admin/settings/general', 'settings/general')->name('settings.general');
expected: Route::view('settings/general', 'settings/general');

Image

[PRIORITY] Create billing_address label type

In AddressLabel module:

  • add BillingAdressLabelShippingService, commit, push
  • create billing_address_label in module service provider (enabling), commit push
  • create migration to add new billing_address_label (because module is already enabled and enabling method wont invoke), commit, push

Ensure all date times on UI are in right format

Database saves all date and times in UTC timezone, our global helper formatting function should be used on all dates in UI

correct usage: formatDateTime(order['order_closed_at'])
https://github.com/CodingCab/ShipTownDev/blob/157f28c3809a267b5bec23039c534f861f80c049/resources/js/components/Orders/OrderCard.vue#L377

todo:

  • click through all pages and check where dates are displayed
  • ensure helper method is used

sample incorrect issue
https://github.com/CodingCab/ShipTownDev/blob/157f28c3809a267b5bec23039c534f861f80c049/resources/js/components/Orders/OrderCard.vue#L364

Image

Image

Image

Feature: Add auto-heal option to heartbeats

  • add auto_heal_job_class column to heartbeats table
  • for all expired heartbeats, execute that auto_heal_job_class each time request is made to api/heartbeats::index
  • update heartbeats auto_heal_job_class for periodic event jobs like every minute, five minutes etc

Image

sample below:

Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign...

Sentry Issue: SHIPTOWN-STAGING-K

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`guineys_products_management`.`inventory_reservations`, CONSTRAINT `inventory_reservations_product_sku_foreign` FOREIGN KEY (`product_sku`) REFERENCES `products` (`sku`) ON DELETE CASCADE ON U)
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 46, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::App\Modules\ActiveOrdersInventoryReservations\src\Listeners\{closure}
    'custom_uuid' => ReservationsService::getUuid($orderProduct),
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 50, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::handle
    });
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Observers/ConfigurationObserver.php", line 12, in App\Modules\ActiveOrdersInventoryReservations\src\Observers\ConfigurationObserver::updated
    ConfigurationUpdatedEvent::dispatch($configuration);
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Http/Controllers/Api/Modules/ActiveOrdersInventoryReservationsController.php", line 23, in App\Modules\ActiveOrdersInventoryReservations\src\Http\Controllers\Api\Modules\ActiveOrdersInventoryReservationsController::update
    $configuration->update($request->validated());
  File "/app/Http/Middleware/AddHeaderAccessToken.php", line 22, in App\Http\Middleware\AddHeaderAccessToken::handle
    return $next($request);
...
(70 additional frame(s) were not displayed)

Doctrine\DBAL\Driver\PDO\Exception: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`guineys_products_management`.`inventory_reservations`, CONSTRAINT `inventory_reservations_product_sku_foreign` FOREIGN KEY (`product_sku`) REFERENCES `products` (`sku`) ON DELETE CASCADE ON U)
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 46, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::App\Modules\ActiveOrdersInventoryReservations\src\Listeners\{closure}
    'custom_uuid' => ReservationsService::getUuid($orderProduct),
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 50, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::handle
    });
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Observers/ConfigurationObserver.php", line 12, in App\Modules\ActiveOrdersInventoryReservations\src\Observers\ConfigurationObserver::updated
    ConfigurationUpdatedEvent::dispatch($configuration);
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Http/Controllers/Api/Modules/ActiveOrdersInventoryReservationsController.php", line 23, in App\Modules\ActiveOrdersInventoryReservations\src\Http\Controllers\Api\Modules\ActiveOrdersInventoryReservationsController::update
    $configuration->update($request->validated());
  File "/app/Http/Middleware/AddHeaderAccessToken.php", line 22, in App\Http\Middleware\AddHeaderAccessToken::handle
    return $next($request);
...
(70 additional frame(s) were not displayed)

Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`guineys_products_management`.`inventory_reservations`, CONSTRAINT `inventory_reservations_product_sku_foreign` FOREIGN KEY (`product_sku`) REFERENCES `products` (`sku`) ON DELETE CASCADE ON U) (SQL: insert into `inventory_reservations` (`inventory_id`, `product_sku`, `warehouse_code`, `quantity_reserved`, `comment`, `custom_uuid`, `updated_at`, `created_at`) values (7736646, 45, NES, 1, Order #1000310526, module_active_orders_inventory_reservations;order_id:347256;order_product_id:615695, 2024-03-19 13:28:15, 2024-03-19 13:28:15))
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 46, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::App\Modules\ActiveOrdersInventoryReservations\src\Listeners\{closure}
    'custom_uuid' => ReservationsService::getUuid($orderProduct),
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Listeners/ConfigurationUpdatedEventListener.php", line 50, in App\Modules\ActiveOrdersInventoryReservations\src\Listeners\ConfigurationUpdatedEventListener::handle
    });
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Observers/ConfigurationObserver.php", line 12, in App\Modules\ActiveOrdersInventoryReservations\src\Observers\ConfigurationObserver::updated
    ConfigurationUpdatedEvent::dispatch($configuration);
  File "/app/Modules/ActiveOrdersInventoryReservations/src/Http/Controllers/Api/Modules/ActiveOrdersInventoryReservationsController.php", line 23, in App\Modules\ActiveOrdersInventoryReservations\src\Http\Controllers\Api\Modules\ActiveOrdersInventoryReservationsController::update
    $configuration->update($request->validated());
  File "/app/Http/Middleware/AddHeaderAccessToken.php", line 22, in App\Http\Middleware\AddHeaderAccessToken::handle
    return $next($request);
...
(67 additional frame(s) were not displayed)

UI - Inventory with fractions is displayed incorrectly

Inventory with fractions is not displayed correctly as its rounds the number

Please check anywhere where NumberCard.vue as this is most likely causing issues.

Steps to reproduce:

  1. Tools > Data Collector
  2. Create new collection
  3. scan product and enter 2.2 quantity
  4. go to Options
  5. Click "Import as stocktake"

Products page
Orders page
Data Collector page
inventory movements report

Image

Image

Image

Add product_sku column to inventory table

after id, nullable

create foreign key

under maintanance module create job which can be ran manually and daily (see Magento2MSI service provider as example)
Settings > General

the job should:
select 1000 products where product_sku is null and fill product id
wait 100ms and repeat the process until no product_sku = null found

[PRIORITY] Order Billing address - Migration, UI updates, Seeders

  • Create migration, update models, resources and api
  • Update order seeders
  • display on UI

Please do the working version with minimal code changes possible and make notes of possible refactor suggestions.

  • Billing Address should be displayed under current shipping address (the same tab), just copy shipping address code and update variables

Image

** Styling

  • Add header above "SHIPPING ADDRESS" & "BILLING ADDRESS"
  • Please copy header style from ProductCard.vue
  • They should be UPPER CASE
  • When the address is null display blank values, do not display records not found etc.../

resources/js/components/Products/ProductCard.vue:116

Image

Inventory Reservations Module Rebuild - Allow multiple reservations

https://reservations-shiptowndev-codingcab.myshiptown.com/dashboard

We did:

  • 1. Create migration for inventory_reservations_table
  • 2. create first basic test
  • 3. make test pass by managing inventory.quantity_reserved in OrderProductUpdatedEventListeners

\App\Modules\InventoryReservations

OrderProductCreatedEventListeners

This should allow multiple systems to reserve inventory for a product, and then when the product is packed, it wil remove the reservation from the inventory record.

Example: (inventory_reservations (id, inventory_id, product_sku, warehouse_code, quantity_reserved, reason, custom_uuid))
Web Orders reserves 2 units,
POS reserves 1 unit,
Warehouse reserves 10 units for a special customer order

In InventoryTotals module, update inventory totals in RecalculateInventoryRecordsJob

inventory.quantity_reserved = 13

this issue has be completed right after: #249
#249

Reports > Activity Log

please refactor to match report standard

  • update template
  • update route to reports/activity-log

PRIORITY - Create "Reports > Inventory Transfers" Report

https://youritsolutions.freshservice.com/a/tickets/50833

Please create report from this query

SELECT
  department_tag.name as department,
  category_tag.name as category,
  data_collections.name as transfer_name,
  products.sku,
  products.name,
  products_prices.cost,
  data_collection_records.total_transferred_in,
  data_collection_records.updated_at

FROM `data_collection_records`

LEFT JOIN data_collections 
  ON data_collections.id = data_collection_records.data_collection_id

LEFT JOIN products
  ON products.id = data_collection_records.product_id

LEFT JOIN tags as department_tag
  ON department_tag.id IN (SELECT tag_id FROM taggables WHERE taggables.taggable_id = data_collection_records.product_id AND taggables.taggable_type = 'App\\Models\\Product')
  AND department_tag.type = 'rms_department_name'

LEFT JOIN tags as category_tag
  ON category_tag.id IN (SELECT tag_id FROM taggables WHERE taggables.taggable_id = data_collection_records.product_id AND taggables.taggable_type = 'App\\Models\\Product')
  AND category_tag.type = 'rms_category_name'

LEFT JOIN products_prices
  ON products_prices.product_id = data_collection_records.product_id
  AND products_prices.warehouse_id = data_collections.warehouse_id

WHERE
  data_collections.warehouse_id = 19
  AND data_collections.name LIKE 'Transfer from 99%'
  AND data_collection_records.updated_at BETWEEN '2023-05-01 00:00:00' AND '2023-08-01 00:00:00'

ORDER BY department, category, transfer_name

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.