bored-programmers / laravel-wolt
Wolt 是一个 Laravel 包,允许您将您的餐厅与 Wolt 平台集成。它提供了一个简单易用的 API,用于同步您的菜单和管理订单。
Requires
- php: >=8.1
- laravel/framework: >=10.0
- spatie/laravel-data: >=4.6
README
Wolt 是一个 Laravel 包,允许您将您的餐厅与 Wolt 平台集成。它提供了一个简单易用的 API,用于同步您的菜单和管理订单。
目录
要求
- PHP 8.1 或更高版本
- Laravel 10.0 或更高版本
安装
要安装 Wolt,您需要运行以下命令
composer require bored-programmers/laravel-wolt
发布配置文件并设置环境变量。
php artisan vendor:publish --tag=wolt-config
更新您的 .env
文件,包括以下变量
WOLT_MENU_API_USERNAME=your_menu_api_username WOLT_MENU_API_PASSWORD=your_menu_api_password WOLT_ORDER_API_KEY=your_order_api_key WOLT_VENUE_ID=your_venue_id WOLT_IS_SANDBOX=true/false
使用
同步菜单
要同步您的菜单与 Wolt,请使用 WoltService::syncMenu
方法。
以下是一个如何使用 DTO 创建菜单并与 Wolt 同步的示例。
use BoredProgrammers\Wolt\DTO\MenuData; use BoredProgrammers\Wolt\DTO\CategoryData; use BoredProgrammers\Wolt\DTO\SubcategoryData; use BoredProgrammers\Wolt\DTO\ItemData; use BoredProgrammers\Wolt\DTO\TranslationData; use BoredProgrammers\Wolt\DTO\CaffeineContentData; use BoredProgrammers\Wolt\DTO\WeeklyAvailabilityData; use BoredProgrammers\Wolt\DTO\WeeklyVisibilityData; use BoredProgrammers\Wolt\DTO\OptionData; use BoredProgrammers\Wolt\DTO\SelectionRangeData; use BoredProgrammers\Wolt\DTO\OptionValueData; use BoredProgrammers\Wolt\DTO\SubOptionValueData; use BoredProgrammers\Wolt\DTO\ProductInformationData; use BoredProgrammers\Wolt\DTO\NutritionInformationData; use BoredProgrammers\Wolt\DTO\NutritionValuesData; use BoredProgrammers\Wolt\DTO\NutrientData; use Spatie\LaravelData\DataCollection; // Example Translations for Category $categoryNameTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Beverages']), TranslationData::from(['lang' => 'fr', 'value' => 'Boissons']) ]); // Example Translations for Subcategory $subCategoryNameTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Hot Drinks']), TranslationData::from(['lang' => 'fr', 'value' => 'Boissons Chaudes']) ]); // Example Translations for Item $itemNameTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Espresso']), TranslationData::from(['lang' => 'fr', 'value' => 'Espresso']) ]); $itemDescriptionTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Rich and bold espresso coffee']), TranslationData::from(['lang' => 'fr', 'value' => 'Café espresso riche et audacieux']) ]); // Example Translations for Options $optionNameTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Milk Type']), TranslationData::from(['lang' => 'fr', 'value' => 'Type de Lait']) ]); $optionValueNameTranslation1 = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Whole Milk']), TranslationData::from(['lang' => 'fr', 'value' => 'Lait entier']) ]); $optionValueNameTranslation2 = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Soy Milk']), TranslationData::from(['lang' => 'fr', 'value' => 'Lait de soja']) ]); // Example Sub-option Value $subOptionValueNameTranslation = new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Vanilla Syrup']), TranslationData::from(['lang' => 'fr', 'value' => 'Sirop de vanille']) ]); // Example Nutrition Information $nutritionInformation = NutritionInformationData::from([ 'serving_size' => 'per_100_ml', 'nutrition_values' => NutritionValuesData::from([ 'energy_kcal' => NutrientData::from(['unit' => 'kcal', 'value' => 5]), 'energy_kj' => NutrientData::from(['unit' => 'kj', 'value' => 20]), 'fats' => NutrientData::from(['unit' => 'g', 'value' => 0.1]), 'saturated_fats' => NutrientData::from(['unit' => 'g', 'value' => 0.05]), 'mono_unsaturated_fats' => NutrientData::from(['unit' => 'g', 'value' => 0.01]), 'poly_unsaturated_fats' => NutrientData::from(['unit' => 'g', 'value' => 0.01]), 'carbohydrate' => NutrientData::from(['unit' => 'g', 'value' => 0.5]), 'sugar' => NutrientData::from(['unit' => 'g', 'value' => 0.1]), 'starch' => NutrientData::from(['unit' => 'g', 'value' => 0.2]), 'polyols' => NutrientData::from(['unit' => 'g', 'value' => 0.0]), 'protein' => NutrientData::from(['unit' => 'g', 'value' => 0.2]), 'salt' => NutrientData::from(['unit' => 'g', 'value' => 0.01]), 'sodium' => NutrientData::from(['unit' => 'mg', 'value' => 5]), 'fibres' => NutrientData::from(['unit' => 'g', 'value' => 0.1]), 'vitamin_c' => NutrientData::from(['unit' => 'mg', 'value' => 0.0]), 'potassium' => NutrientData::from(['unit' => 'mg', 'value' => 80]), 'calcium' => NutrientData::from(['unit' => 'mg', 'value' => 10]), 'magnesium' => NutrientData::from(['unit' => 'mg', 'value' => 2]), 'chloride' => NutrientData::from(['unit' => 'mg', 'value' => 5]), 'fluoride' => NutrientData::from(['unit' => 'mg', 'value' => 0.0]) ]) ]); // Example Product Information $productInformation = ProductInformationData::from([ 'ingredients' => new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Water, Coffee Beans']), TranslationData::from(['lang' => 'fr', 'value' => 'Eau, Grains de café']) ]), 'additives' => new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'None']), TranslationData::from(['lang' => 'fr', 'value' => 'Aucun']) ]), 'nutrition_facts' => new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Low calories']), TranslationData::from(['lang' => 'fr', 'value' => 'Faible en calories']) ]), 'nutrition_information' => $nutritionInformation, 'allergens' => new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'None']), TranslationData::from(['lang' => 'fr', 'value' => 'Aucun']) ]), 'producer_information' => new DataCollection([ TranslationData::from(['lang' => 'en', 'value' => 'Local Roastery']), TranslationData::from(['lang' => 'fr', 'value' => 'Torréfacteur local']) ]) ]); // Example Option with Sub-option Values $optionValue1 = OptionValueData::from([ 'name' => $optionValueNameTranslation1, 'selection_range' => SelectionRangeData::from(['min' => 0, 'max' => 1]), 'price' => 0.50, 'enabled' => true, 'default' => true, 'external_data' => 'option-value-1', 'sub_option_values' => new DataCollection([ SubOptionValueData::from([ 'name' => $subOptionValueNameTranslation, 'selection_range' => SelectionRangeData::from(['min' => 0, 'max' => 1]), 'price' => 0.20, 'enabled' => true, 'default' => false, 'external_data' => 'sub-option-value-1' ]) ]) ]); $optionValue2 = OptionValueData::from([ 'name' => $optionValueNameTranslation2, 'selection_range' => SelectionRangeData::from(['min' => 0, 'max' => 1]), 'price' => 0.60, 'enabled' => true, 'default' => false, 'external_data' => 'option-value-2', 'sub_option_values' => null ]); $option = OptionData::from([ 'name' => $optionNameTranslation, 'type' => 'SingleChoice', 'selection_range' => SelectionRangeData::from(['min' => 1, 'max' => 1]), 'external_data' => 'option-1', 'values' => new DataCollection([$optionValue1, $optionValue2]) ]); // Example Item $item = ItemData::from([ 'name' => $itemNameTranslation, 'description' => $itemDescriptionTranslation, 'image_url' => 'https://example.com/espresso.jpg', 'price' => 2.99, 'sales_tax_percentage' => 0.07, 'alcohol_percentage' => null, 'caffeine_content' => CaffeineContentData::from(['serving_size' => 'per_100_ml', 'value' => 212.0]), 'weekly_availability' => new DataCollection([ WeeklyAvailabilityData::from([ 'opening_day' => 'MONDAY', 'opening_time' => '08:00', 'closing_day' => 'MONDAY', 'closing_time' => '20:00' ]) ]), 'weekly_visibility' => new DataCollection([ WeeklyVisibilityData::from([ 'opening_day' => 'MONDAY', 'opening_time' => '08:00', 'closing_day' => 'MONDAY', 'closing_time' => '20:00' ]) ]), 'enabled' => true, 'delivery_methods' => ['takeaway', 'homedelivery'], 'options' => new DataCollection([$option]), 'external_data' => 'item-espresso-001', 'product_information' => $productInformation ]); // Example Subcategory $subcategory = SubcategoryData::from([ 'name' => $subCategoryNameTranslation, 'description' => null, 'items' => new DataCollection([$item]) ]); // Example Category $category = CategoryData::from([ 'name' => $categoryNameTranslation, 'description' => null, 'subcategories' => new DataCollection([$subcategory]) ]); // Example Menu $menu = MenuData::from([ 'currency' => 'USD', 'primary_language' => 'en', 'categories' => new DataCollection([$category]) ]); $response = WoltService::syncMenu($menuData);
获取订单
要检索订单,请使用 WoltService::getOrder
方法。
您将从 Wolt 调用的 webhook 中获取订单 ID。
更多关于此的信息 > Wolt Webhook 文档。
我建议使用
spatie/laravel-webhook-client
包来处理 webhook。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::getOrder($orderId);
接受订单
要接受订单,请使用 WoltService::acceptOrder
方法。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::acceptOrder($orderId);
拒绝订单
要拒绝订单,请使用 WoltService::rejectOrder
方法。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::rejectOrder($orderId);
标记订单为准备就绪
要标记订单为准备就绪,请使用 WoltService::markReadyOrder
方法。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::markReadyOrder($orderId);
标记订单为已送达
要标记订单为已送达,请使用 WoltService::markDeliveredOrder
方法。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::markDeliveredOrder($orderId);
确认预订
要确认预订,请使用 WoltService::confirmPreorder
方法。
use BoredProgrammers\Wolt\WoltService; $orderId = 'your_wolt_order_id'; $response = WoltService::confirmPreorder($orderId);
贡献指南
我们欢迎为 Wolt 做出贡献。如果您想做出贡献,请 fork 仓库,进行更改,并提交 pull request。我们对贡献有一些要求
- 遵循 PSR-2 编码标准。
- 仅使用 pull request 进行贡献。
变更日志
有关更改的详细历史记录,请参阅 GitHub 上的 发行版。
许可
本项目采用 MIT 许可证。
联系方式
如有任何问题或疑虑,请随时在 GitHub 上创建 讨论。
鸣谢
由 Matěj Černý 从 Bored Programmers 创建。
致谢
我们感谢所有帮助使 Wolt 成为更好的包的贡献者。