As a programmer developing software, in order to develop the system, we must first sort out the product requirements, and the product function analysis first. From the perspective of business model, a good software system must comply with the product design concept, and the product flow should be carried out by the user's self driving, interesting, rewarding and incentive behavior. In the process of developing huile optimization system, The key points of product functions are summarized as follows. Welcome to discuss and communicate. Micro signal: toudouge
Next, I will explain the development of huile optimization system from three parts
1, Member function introduction
2, Introduction to incentive and reward mechanism
3, System core source code sharing
1, Introduction to member functions of the system
Member group behavior design
1. Each account and each category can participate in the group 20 times a day
2.20 people participated in the group, of which only one was successful
3. When the number of people in the group is full, the group will be opened, and the group will be dissolved if it is not full in 60 minutes. If the number of people is less than the number, the group will be dissolved without deducting the number of groups in that day
4. According to the number of people in the group set for each commodity, those who win the group will get the group goods. For similar commodities that win the group 5 times in total, you can choose four of them for consignment, choose one of them to ship for your own use, and refund if you fail to win the group. All those who participate in the group can receive a random cash red envelope of 0.1 yuan to 3 yuan. The income part is settled and withdrawn from T+0 and withdrawn from 10 yuan (withdrawal service fee is 6%)
5.SVIP subsidizes one group fight, enjoys automatic group fight, and enjoys membership status (ordinary members can participate in the group 20 times, and SVIP members can open the group 21 times)
6. In the early stage, five special areas were opened, and each special area can spell the group income up to 20 times a day; The five zones can fight 100 times a day (20 people in each group). Each group, whether it is successful or not, will have a corresponding red envelope reward. The minimum threshold is 30 yuan. You can join the group (4 pieces can be consigned for 5 times, and one piece can be shipped). The red envelope amount ranges from 0.1 to 3 yuan
2, Introduction to incentive and reward mechanism
Bonus driven design
1. Recommendation Award
5% cash reward for the first order of self invitation (real-time arrival, cash withdrawal)
2. Promotion system:
LV1: direct push of 5 valid, 5% of friends' red envelope income, 2% of team red envelope income, LV2: direct push of 10 valid and 30 valid, 10% of friends' red envelope income, 3% of team red envelope income, LV3: direct push of 30 valid and 80 valid, 15% of friends' red envelope income, 4% of team red envelope income, 10% of peer income, LV2: direct push of 50 valid and 600 valid, 20% of friends' red envelope income, The team's red envelope income is 5%, and the peer income is 10%
3. Bonus pool dividend design
Take 5% of the amount of each order in the fight into the ranking bonus pool, and directly invite the top 10 members of the number of effective members to pay dividends in proportion
Dividend ratio:
The first 30%, the second 18%, the third 12%, the fourth 8%, the fifth 7%, the sixth 6%, the seventh 6%, the eighth 5%, the ninth 5%, and the tenth 3%; At 23 o'clock every day, the bonus pool will be cleared after the dividend, and the bonus pool amount will continue to accumulate the next day
3, Share the core source code of the system
The following is the core source code of the system
/** * Dough processing * @param $cartInfo * @return array */ public static function getCombinationOrderPriceGroup($cartInfo) { $storePostage = floatval(sys_config('store_postage')) ?: 0; $storeFreePostage = floatval(sys_config('store_free_postage')) ?: 0; $totalPrice = self::getCombinationOrderTotalPrice($cartInfo); $costPrice = self::getCombinationOrderTotalPrice($cartInfo); if (!$storeFreePostage) { $storePostage = 0; } else { foreach ($cartInfo as $cart) { if (!StoreCombination::where('id', $cart['combination_id'])->value('is_postage')) $storePostage = bcadd($storePostage, StoreCombination::where('id', $cart['combination_id'])->value('postage'), 2); } if ($storeFreePostage <= $totalPrice) $storePostage = 0; } return compact('storePostage', 'storeFreePostage', 'totalPrice', 'costPrice'); } /** * Group price * @param $cartInfo * @return float */ public static function getCombinationOrderTotalPrice($cartInfo) { $totalPrice = 0; foreach ($cartInfo as $cart) { if ($cart['combination_id']) { $totalPrice = bcadd($totalPrice, bcmul($cart['cart_num'], StoreCombination::where('id', $cart['combination_id'])->value('price'), 2), 2); } } return (float)$totalPrice; } /** * Cache order information * @param $uid * @param $cartInfo * @param $priceGroup * @param array $other * @param int $cacheTime * @return string * @throws \Psr\SimpleCache\InvalidArgumentException */ public static function cacheOrderInfo($uid, $cartInfo, $priceGroup, $other = [], $cacheTime = 600) { $key = md5(time()); Cache::set('user_order_' . $uid . $key, compact('cartInfo', 'priceGroup', 'other'), $cacheTime); return $key; } /** * Get order cache information * @param $uid * @param $key * @return mixed|null * @throws \Psr\SimpleCache\InvalidArgumentException */ public static function getCacheOrderInfo($uid, $key) { $cacheName = 'user_order_' . $uid . $key; if (!Cache::has($cacheName)) return null; return Cache::get($cacheName); } /** * Delete order cache * @param $uid * @param $key */ public static function clearCacheOrderInfo($uid, $key) { Cache::delete('user_order_' . $uid . $key); } /** * Generate order * @param $uid * @param $key * @param $addressId * @param $payType * @param bool $useIntegral * @param int $couponId * @param string $mark * @param int $combinationId * @param int $pinkId * @param int $seckill_id * @param int $bargain_id * @param bool $test * @param int $isChannel * @param int $shipping_type * @param string $real_name * @param string $phone * @return StoreOrder|bool|\think\Model * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function cacheKeyCreateOrder($uid, $key, $addressId, $payType, $useIntegral = false, $couponId = 0, $mark = '', $combinationId = 0, $pinkId = 0, $seckill_id = 0, $bargain_id = 0, $test = false, $isChannel = 0, $shipping_type = 1, $real_name = '', $phone = '', $storeId = 0, $is_auto = 0) { self::beginTrans(); try { $shipping_type = (int)$shipping_type; $offlinePayStatus = (int)sys_config('offline_pay_status') ?? (int)2; if ($offlinePayStatus == 2) unset(self::$payType['offline']); if (!array_key_exists($payType, self::$payType)) return self::setErrorInfo('Wrong choice of payment method!', true); if (self::be(['unique' => $key, 'uid' => $uid])) return self::setErrorInfo('Do not submit orders repeatedly', true); $userInfo = User::getUserInfo($uid); if (!$userInfo) return self::setErrorInfo('user does not exist!', true); $cartGroup = self::getCacheOrderInfo($uid, $key); if (!$cartGroup) return self::setErrorInfo('The order has expired,Please refresh the current page!', true); $cartInfo = $cartGroup['cartInfo']; $check_hour = intval(date('H')); //$check_goods_info = StoreProduct::field('start_hour,stop_hour')->where('id',$cartInfo[0]['productInfo']['id'])->find()->toArray(); if( $check_hour < 6 || $check_hour >= 22 ) return self::setErrorInfo('It is not yet time for the delegation to participate', true); if( StoreOrderSpell::where('uid="'.$uid.'" AND goods_id = "'.$cartInfo[0]['productInfo']['id'].'" AND is_pay = 1 AND status = 0')->count() > 0 ) return self::setErrorInfo('You are already in the queue. Please do not participate again!', true); $priceGroup = $cartGroup['priceGroup']; $other = $cartGroup['other']; $payPrice = (float)$priceGroup['totalPrice']; $addr = UserAddress::where('uid', $uid)->where('id', $addressId)->find(); if ($payType == 'offline' && sys_config('offline_postage') == 1) { $payPostage = 0; } else { $payPostage = self::getOrderPriceGroup($cartInfo, $addr)['storePostage']; } if ($shipping_type === 1) { if (!$test && !$addressId) return self::setErrorInfo('Please select a shipping address!', true); if (!$test && (!UserAddress::be(['uid' => $uid, 'id' => $addressId, 'is_del' => 0]) || !($addressInfo = UserAddress::find($addressId)))) return self::setErrorInfo('Wrong address selection!', true); } else { if ((!$real_name || !$phone) && !$test) return self::setErrorInfo('Please fill in your name and telephone number', true); $addressInfo['real_name'] = $real_name; $addressInfo['phone'] = $phone; $addressInfo['province'] = ''; $addressInfo['city'] = ''; $addressInfo['district'] = ''; $addressInfo['detail'] = ''; } $cartIds = []; $totalNum = 0; $gainIntegral = 0; foreach ($cartInfo as $cart){ if (!$test && !self::checkProductStock($uid, $cart['product_id'], $cart['cart_num'], $cart['product_attr_unique'], $cart['combination_id'], $cart['seckill_id'], $cart['bargain_id'])) { return false; } $cartIds[] = $cart['id']; $totalNum += $cart['cart_num']; if (!$seckill_id) $seckill_id = $cart['seckill_id']; if (!$bargain_id) $bargain_id = $cart['bargain_id']; if (!$combinationId) $combinationId = $cart['combination_id']; $cartInfoGainIntegral = isset($cart['productInfo']['give_integral']) ? bcmul($cart['cart_num'], $cart['productInfo']['give_integral'], 2) : 0; $gainIntegral = bcadd($gainIntegral, $cartInfoGainIntegral, 2); } $deduction = $seckill_id || $bargain_id || $combinationId; if ($deduction) { $couponId = 0; $useIntegral = false; if (!$test) { unset(self::$payType['offline']); if (!array_key_exists($payType, self::$payType)) return self::setErrorInfo('Offline payment cannot be used for marketing products!', true); } } //Use coupons $res1 = true; if ($couponId) { $couponInfo = StoreCouponUser::validAddressWhere()->where('id', $couponId)->where('uid', $uid)->find(); if (!$couponInfo) return self::setErrorInfo('The coupon selected is invalid!', true); $coupons = StoreCouponUser::getUsableCouponList($uid, ['valid' => $cartInfo], $payPrice); $flag = false; foreach ($coupons as $coupon) { if ($coupon['id'] == $couponId) { $flag = true; continue; } } if (!$flag) return self::setErrorInfo('It does not meet the conditions for using the coupon!', true); $payPrice = (float)bcsub($payPrice, $couponInfo['coupon_price'], 2); $res1 = StoreCouponUser::useCoupon($couponId); $couponPrice = $couponInfo['coupon_price']; } else { $couponId = 0; $couponPrice = 0; } if (!$res1) return self::setErrorInfo('Failed to use coupon!', true); //$shipping_type = 1 express shipment $shipping_type = 2 store self withdrawal $store_self_mention = sys_config('store_self_mention') ?? 0; if (!$store_self_mention) $shipping_type = 1; if ($shipping_type === 1) { //Package mail if ((isset($other['offlinePostage']) && $other['offlinePostage'] && $payType == 'offline')) $payPostage = 0; $payPrice = (float)bcadd($payPrice, $payPostage, 2); } else if ($shipping_type === 2) { //The store picked it up without postage payment $priceGroup['storePostage'] = 0; $payPostage = 0; if (!$storeId && !$test) { return self::setErrorInfo('Please select a store', true); } } //Integral deduction $res2 = true; $SurplusIntegral = 0; $useIntegral = false; if ($useIntegral && $userInfo['integral'] > 0) { $deductionPrice = (float)bcmul($userInfo['integral'], $other['integralRatio'], 2); if ($deductionPrice < $payPrice) { $payPrice = bcsub($payPrice, $deductionPrice, 2); $usedIntegral = $userInfo['integral']; $SurplusIntegral = 0; $res2 = false !== User::edit(['integral' => 0], $userInfo['uid'], 'uid'); } else { $deductionPrice = $payPrice; $usedIntegral = (float)bcdiv($payPrice, $other['integralRatio'], 2); $SurplusIntegral = bcsub($userInfo['integral'], $usedIntegral, 2); $res2 = false !== User::bcDec($userInfo['uid'], 'integral', $usedIntegral, 'uid'); $payPrice = 0; } $res2 = $res2 && false != UserBill::expend('Integral deduction', $uid, 'integral', 'deduction', $usedIntegral, $key, $userInfo['integral'], 'Use of purchased goods' . floatval($usedIntegral) . 'Integral deduction' . floatval($deductionPrice) . 'element'); } else { $deductionPrice = 0; $usedIntegral = 0; } if (!$res2) return self::setErrorInfo('Use of points deduction failed!', true); if ($payPrice <= 0) $payPrice = 0; if ($test) { self::rollbackTrans(); return [ 'total_price' => $priceGroup['totalPrice'], 'pay_price' => $payPrice, 'pay_postage' => $payPostage, 'coupon_price' => $couponPrice, 'deduction_price' => $deductionPrice, 'SurplusIntegral' => $SurplusIntegral, ]; } $orderInfo = [ 'uid' => $uid, 'order_id' => $test ? 0 : self::getNewOrderId(), 'real_name' => $addressInfo['real_name'], 'user_phone' => $addressInfo['phone'], 'user_address' => $addressInfo['province'] . ' ' . $addressInfo['city'] . ' ' . $addressInfo['district'] . ' ' . $addressInfo['detail'], 'cart_id' => $cartIds, 'total_num' => $totalNum, 'total_price' => $priceGroup['totalPrice'], 'total_postage' => $priceGroup['storePostage'], 'coupon_id' => $couponId, 'coupon_price' => $couponPrice, 'pay_price' => $payPrice, 'pay_postage' => $payPostage, 'deduction_price' => $deductionPrice, 'paid' => 0, 'pay_type' => $payType, 'use_integral' => $usedIntegral, 'gain_integral' => $gainIntegral, 'mark' => htmlspecialchars($mark), 'combination_id' => $combinationId, 'pink_id' => $pinkId, 'seckill_id' => $seckill_id, 'bargain_id' => $bargain_id, 'cost' => $priceGroup['costPrice'], 'is_channel' => $isChannel, 'add_time' => time(), 'unique' => $key, 'shipping_type' => $shipping_type, ]; if ($shipping_type === 2) { $orderInfo['verify_code'] = self::getStoreCode(); $orderInfo['store_id'] = SystemStore::getStoreDispose($storeId, 'id'); if (!$orderInfo['store_id']) return self::setErrorInfo('There is no store at present. You can't select store self collection!', true); } $order = self::create($orderInfo); if (!$order) return self::setErrorInfo('Order generation failed!', true); $res5 = true; foreach ($cartInfo as $cart) { //Minus inventory plus sales if ($combinationId) $res5 = $res5 && StoreCombination::decCombinationStock($cart['cart_num'], $combinationId, isset($cart['productInfo']['attrInfo']) ? $cart['productInfo']['attrInfo']['unique'] : ''); else if ($seckill_id) $res5 = $res5 && StoreSeckill::decSeckillStock($cart['cart_num'], $seckill_id, isset($cart['productInfo']['attrInfo']) ? $cart['productInfo']['attrInfo']['unique'] : ''); else if ($bargain_id) $res5 = $res5 && StoreBargain::decBargainStock($cart['cart_num'], $bargain_id, isset($cart['productInfo']['attrInfo']) ? $cart['productInfo']['attrInfo']['unique'] : ''); else $res5 = $res5 && StoreProduct::decProductStock($cart['cart_num'], $cart['productInfo']['id'], isset($cart['productInfo']['attrInfo']) ? $cart['productInfo']['attrInfo']['unique'] : ''); } //Save cart item information $res4 = false !== StoreOrderCartInfo::setCartInfo($order['id'], $cartInfo); $res7 = $res8 = true; if($cartInfo[0]['productInfo']['id']) { $user_info = User::getUserInfo($uid); $insert_spell_data = [ 'uid' => $uid, 'nickname' => $user_info['nickname'], 'oid' => $order['id'], 'goods_id' => $cartInfo[0]['productInfo']['id'], 'status' => 0, 'is_auto' => $is_auto, 'is_pay' => 0, 'edit_time' => time(), 'add_time' => time(), ]; $res7 = StoreOrderSpell::insert($insert_spell_data); //If there is no record in the system, a new one will be added if( StoreOrderSpellUserLog::where('uid="'.$uid.'" AND goods_id="'.$cartInfo[0]['productInfo']['id'].'"')->count() == 0) { $insert_user_log = [ 'goods_id' => $cartInfo[0]['productInfo']['id'], 'uid' => $uid, ]; $res8 = StoreOrderSpellUserLog::insert($insert_user_log); } } //Shopping cart status modification $res6 = false !== StoreCart::where('id', 'IN', $cartIds)->update(['is_pay' => 1]); if (!$res4 || !$res5 || !$res6 || !$res7 || !$res8) return self::setErrorInfo('Order generation failed!', true); //Automatically set default address UserRepository::storeProductOrderCreateEbApi($order, compact('cartInfo', 'addressId')); self::clearCacheOrderInfo($uid, $key); self::commitTrans(); StoreOrderStatus::status($order['id'], 'cache_key_create_order', 'Order generation'); return $order; } catch (\PDOException $e) { self::rollbackTrans(); return self::setErrorInfo('When generating an order SQL Execution error reason:' . $e->getMessage()); } catch (\Exception $e) { self::rollbackTrans(); return self::setErrorInfo('System error generating order. Error reason:' . $e->getMessage()); } } /** * Fallback integral * @param $order Order information * @return bool */ public static function RegressionIntegral($order) { if ($order['paid'] || $order['status'] == -2 || $order['is_del']) return true; if ($order['use_integral'] <= 0) return true; if ((int)$order['status'] != -2 && (int)$order['refund_status'] != 2 && $order['back_integral'] >= $order['use_integral']) return true; $res = User::bcInc($order['uid'], 'integral', $order['use_integral']); if (!$res) return self::setErrorInfo('Failed to increase fallback points'); UserBill::income('Integral fallback', $order['uid'], 'integral', 'deduction', $order['use_integral'], $order['unique'], User::where('uid', $order['uid'])->value('integral'), 'Failed to purchase goods,Fallback integral' . floatval($order['use_integral'])); return false !== self::where('order_id', $order['order_id'])->update(['back_integral' => $order['use_integral']]); } /** * Return inventory and sales * @param $order Order information * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function RegressionStock($order) { if ($order['status'] == -2 || $order['is_del']) return true; $combinationId = $order['combination_id']; $seckill_id = $order['seckill_id']; $bargain_id = $order['bargain_id']; $res5 = true; $cartInfo = StoreOrderCartInfo::where('cart_id', 'in', $order['cart_id'])->select(); foreach ($cartInfo as $cart) { //Increase inventory decrease sales if ($combinationId) $res5 = $res5 && StoreCombination::incCombinationStock($cart['cart_info']['cart_num'], $combinationId, isset($cart['cart_info']['productInfo']['attrInfo']) ? $cart['cart_info']['productInfo']['attrInfo']['unique'] : ''); else if ($seckill_id) $res5 = $res5 && StoreSeckill::incSeckillStock($cart['cart_info']['cart_num'], $seckill_id, isset($cart['cart_info']['productInfo']['attrInfo']) ? $cart['cart_info']['productInfo']['attrInfo']['unique'] : ''); else if ($bargain_id) $res5 = $res5 && StoreBargain::incBargainStock($cart['cart_info']['cart_num'], $bargain_id, isset($cart['cart_info']['productInfo']['attrInfo']) ? $cart['cart_info']['productInfo']['attrInfo']['unique'] : ''); else $res5 = $res5 && StoreProduct::incProductStock($cart['cart_info']['cart_num'], $cart['cart_info']['productInfo']['id'], isset($cart['cart_info']['productInfo']['attrInfo']) ? $cart['cart_info']['productInfo']['attrInfo']['unique'] : ''); } return $res5; }