Как обновлять и вставлять данные нескольких строк одновременно нажатием кнопки (ax ios + laravel + vuejs) - PullRequest
0 голосов
/ 28 февраля 2020

каждый, я хочу сделать форму коммерческого предложения с функцией редактирования, поэтому, если пользователь допустит ошибку при вводе данных, он сможет редактировать, обновлять и добавлять другие элементы. И да, я все еще учусь и в этом разбираюсь ie.

Последняя информация, которую я получил от Google, использует топор ios .all, но я не знаю, как его использовать, уже ищу неделю и все еще застрял с этой проблемой.

Основная проблема в деталях. vue и SalesQuotationsController. php.

Я пытался дать вам как можно больше информации, надеюсь, она поможет Вы идентифицировали его.

Спасибо.

API

  1. API. php

    <?php
    
    use Illuminate\Http\Request;
    
    Route::post('/login', 'Auth\LoginController@login');
    
    Route::group(['middleware' => 'auth:api'], function() {
    
    Route::resource('/salesquotation', 'API\SalesQuotationsController')->except(['create', 'show', 'update']);
    Route::post('/salesquotation/insertProduct', 'API\SalesQuotationsController@insertProduct');
    Route::post('/salesquotation/{id}', 'API\SalesQuotationsController@update');
    });
    

Javascript

store. js

import Vue from 'vue'

import Vuex from 'vuex'

import authVuex from './stores/auth.js'        
import sqVuex from './stores/salesquotation.js'


Vue.use(Vuex)


const store = new Vuex.Store({
modules: {
    authVuex,         
    sqVuex

},
  state: {
    token: localStorage.getItem('token'),
    errors: []
},
getters: {

    isAuth: state => {
        return state.token != "null" && state.token != null
    }
},
mutations: {

    SET_TOKEN(state, payload) {
        state.token = payload
    },
    SET_ERRORS(state, payload) {
        state.errors = payload
    },
    CLEAR_ERRORS(state) {
        state.errors = []
    }
}
})

export default store

router. js

import Vue from 'vue'
import Router from 'vue-router'
import store from './store.js'

import IndexSalesQuotation from './pages/transactions/salesquotation/Index.vue'
import ListSalesQuotation from './pages/transactions/salesquotation/List.vue'
import AddSalesQuotation from './pages/transactions/salesquotation/Add.vue'
import EditSalesQuotation from './pages/transactions/salesquotation/Edit.vue'


Vue.use(Router)

const router = new Router({
    mode: 'history',
    routes: [
        {
            path: '/salesquotation',
            component: IndexSalesQuotation,
            meta: { requiresAuth: true },
            children: [
                {
                    path: 'list',
                    name: 'salesQuotRoute.showList',
                    component: ListSalesQuotation,
                    meta: { title: 'Sales Quotation' }
                },
                {
                    path: 'add',
                    name: 'salesQuotRoute.add',
                    component: AddSalesQuotation,
                    meta: { title: 'Create New Sales Quotation' }
                },
                {
                    path: 'edit/:id',
                    name: 'salesQuotRoute.edit',
                    component: EditSalesQuotation,
                    meta: { title: 'Edit Sales Quotation' }
                },                      
            ]
        },
    ]
});

export default router

app. js

import Vue from 'vue'
import router from './router.js'
import store from './store.js'
import App from './App.vue'

import BootstrapVue from 'bootstrap-vue'
import VueSweetalert2 from 'vue-sweetalert2'

Vue.use(VueSweetalert2)
Vue.use(BootstrapVue)

import 'sweetalert2/dist/sweetalert2.min.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

import { mapActions, mapGetters, mapState } from 'vuex'

Vue.component('my-cur-input', {
    props: ["value"],
    template: `
        <div>
            <input type="text" v-model="displayValue" @blur="isInputActive = false"  @focus="isInputActive = true" style="width:100px"/>
        </div>`,
    data: function() {
        return {
            // value = 0,
            isInputActive: false
        }
    },
    computed: {
        displayValue: {
            get: function() {
                if (this.isInputActive) {
                    return this.value.toString()
                } else {
                    var stro = this.value;
                    stro = parseFloat(stro).toFixed(2).split('.');
                    if (stro[0].length >= 4) {
                        stro[0] = stro[0].replace(/(\d)(?=(\d{3})+$)/g, '$1.');
                    }                           
                    return "Rp " + stro.join(',');
                }
            },
            set: function(modifiedValue) {

                let newValue = parseFloat(modifiedValue.replace(/[^\d\.]/g, ""))
                let value = this.value

                if (isNaN(newValue)) {
                    newValue = 0
                }
                this.$emit('input', newValue)
                this.$emit('blur', newValue)
            }
        }
    }
});

new Vue({
    el: '#raz',
    router,
    store,
    components: {
        App
    },
    computed: {
        ...mapGetters(['isAuth']),
        ...mapState(['token']),
        ...mapState('userVuex', {
            user_authenticated: state => state.authenticated
        })
    },

    methods: {
        ...mapActions('userVuex', ['getUserLogin']),

    watch: {
        token() {
        },
        user_authenticated() {
        }
    },
    created() {
        if (this.isAuth) {
            this.getUserLogin()
        }
    }
})

API. js

import axios from 'axios';
import store from './store.js'

const $axios = axios.create({
    baseURL: '/api',
    headers: {
        'Content-Type': 'application/json'
    }
});

$axios.interceptors.request.use (
    function (config) {
        const token = store.state.token
        if (token) config.headers.Authorization = `Bearer ${token}`;
        return config;
    },
    function (error) {
        return Promise.reject (error);
    }
);        
export default $axios;

биржа продаж. js

import $axios from '../api.js'

const state = () => ({
    custitems: [], 
    items: [], 
    units: [],
    custs: [],
    list_sq: [],
    detail_sq: [],
    page: 1,
    idForEdit: ''           
})

const mutations = {

    ASSIGN_CUSTEM(state, payload) {
        state.custitems = payload
    },
    ASSIGN_ITEM(state, payload) {
        state.items = payload
    },
    ASSIGN_UNITS(state, payload) {
        state.units = payload
    },
    ASSIGN_CUST(state, payload) {
        state.custs = payload
    },
    ASSIGN_DETAIL(state, payload) {
        state.detail_sq = payload
    },
    ASSIGN_LIST(state, payload) {
        state.list_sq = payload
    },
    SET_PAGE(state, payload) {
        state.page = payload
    },
    SET_ID_UPDATE(state, payload) {
        state.idForEdit = payload
    }
}

const actions = {

    getUnit({ commit }) {
        return new Promise((resolve, reject) => {
            $axios.get(`/unit`)
            .then((response) => {
                commit('ASSIGN_UNITS', response.data.data)
                resolve(response.data)
            })
        })
    },

    getProd({ commit, state }, payload) {
        let search = payload.search
        payload.loading(true)
        return new Promise((resolve, reject) => {
            $axios.get(`/custem?page=${state.page}&q=${search}`)
            .then((response) => {
                commit('ASSIGN_CUSTEM', response.data)
                payload.loading(false)
                resolve(response.data)
            })
        })
    },
    getCust({ commit, state }, payload) {
        let search = payload.search
        payload.loading(true)
        return new Promise((resolve, reject) => {
            $axios.get(`/cust?page=${state.page}&q=${search}`)
            .then((response) => {
                commit('ASSIGN_CUST', response.data)
                payload.loading(false)
                resolve(response.data)
            })
        })
    },
    createSalesQuot({commit}, payload) {
        return new Promise((resolve, reject) => {
            $axios.post(`/salesquotation`, payload)
            .then((response) => {
                resolve(response.data)
            })
        })
    },
    insertProduct({commit}, payload) {
        return new Promise((resolve, reject) => {
            $axios.post(`/salesquotation/insertProduct`, payload)
            .then((response) => {
                resolve(response.data)
            })
        })
    },
    getListSalesQuot({ commit, state }, payload) {
        let search = typeof payload.search != 'undefined' ? payload.search:''
        let status = typeof payload.status != 'undefined' ? payload.status:''
            return new Promise((resolve, reject) => {
                $axios.get(`/salesquotation?page=${state.page}&q=${search}&status=${status}`)
                .then((response) => {
                    commit('ASSIGN_LIST', response.data)
                    resolve(response.data)
            })
        })
    },
    getDetailSalesQuot({ commit }, payload) {
        return new Promise((resolve, reject) => {
            $axios.get(`/salesquotation/${payload}/edit`)
            .then((response) => {
                commit('ASSIGN_DETAIL', response.data.data)
                resolve(response.data)
            })
        })
    },
    editSalesQuot({ commit }, payload) {
        return new Promise((resolve, reject) => {
            $axios.get(`/salesquotation/${payload}/edit`)
            .then((response) => {
                resolve(response.data)
            })
        })
    },
    updateSalesQuot({ commit }, payload) {
        return new Promise((resolve, reject) => {
            $axios.put(`/salesquotation/${payload.id}`, payload)
            .then((response) => {
                resolve(response.data)
            })
            .catch((error) => {
                if (error.response.status == 422) {
                    commit('SET_ERRORS', error.response.data.errors, { root: true })
                }
            })
        })
    },
}

export default {
    namespaced: true,
    state,
    actions,
    mutations
}

Vue

  1. Список. vue

    <template>
        <div class="col-md-12">
            <div class="panel">
                <div class="panel-heading">
                    <router-link :to="{ name: 'salesQuotRoute.add' }" class="btn btn-primary btn-sm btn-flat">Create Sales Quotation</router-link>
                    <div class="pull-right">
                        <div class="row">                      
    
                            <div class="col-md-6">
                                <select v-model="filter_status" class="form-control">
                                    <option value="3">All</option>
                                    <option value="cancel">Canceled</option>
                                    <option value="done">Done</option>
                                    <option value="open">Open</option>
                                </select>
                            </div>
    
                            <div class="col-md-6">
                                <input type="text" class="form-control" placeholder="Search..." v-model="search">
                            </div>
    
                        </div>
                    </div>
                </div>
    
                <hr>
    
                <div class="panel-body">
                    <b-table striped hover bordered responsive :items="listSQForm.data" :fields="fields" show-empty>
                        <template v-slot:cell(master_cust_id)="row">
                            <p>Name: <strong>{{ row.item.customer ? row.item.customer.cust_name:'' }}</strong></p>
                            <p>Telp: {{ row.item.customer.phone }}</p>
                            <p>Add: {{ row.item.customer.address1 }}</p>
                        </template>
                        <template v-slot:cell(amount)="row">
                            <p>{{ row.item.amount | currency }}</p>
                        </template>
                        <template v-slot:cell(status)="row">
                            <p v-html="row.item.status_label"></p>
                        </template>
                        <template v-slot:cell(actions)="row">
                            <router-link :to="{ name: 'salesQuotRoute.edit', params: {id: row.item.id} }" class="btn btn-warning btn-sm"><i class="fa fa-pencil"></i></router-link>
                        </template>
                    </b-table>
    
                    <div class="row">
                        <div class="col-md-6">
                            <p v-if="listSQForm.data"><i class="fa fa-bars"></i> {{ listSQForm.data.length }} item dari {{ listSQForm.meta.total }} total data</p>
                        </div>
                        <div class="col-md-6">
                            <div class="pull-right">
                                <b-pagination
                                    v-model="page"
                                    :total-rows="listSQForm.meta.total"
                                    :per-page="listSQForm.meta.per_page"
                                    aria-controls="listSQForm"
                                    v-if="listSQForm.data && listSQForm.data.length > 0"
                                    ></b-pagination>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    import { mapActions, mapState } from 'vuex'
    
    export default {
        name: 'DataSalesQuotation',
        created() {
            this.getListSalesQuot({
                status: this.filter_status,
                search: this.search
            }) 
        },
        data() {
            return {
                fields: [
                    { key: 'sq_number', label: 'Quotation'},
                    { key: 'master_cust_id', label: 'Customer' },
                    { key: 'amount', label: 'Amount' },
                    { key: 'description', label: 'Description' },
                    { key: 'proforma_invoice_number', label: 'Proforma Invoice' },
                    { key: 'status', label: 'Status' },
                    { key: 'sales_order_number', label: 'SO Number' },
                    { key: 'actions', label: 'Action' }
    
                ],
                search: '',
                filter_status: 3
            }
        },
        computed: {
            ...mapState('sqVuex', {
                listSQForm: state => state.list_sq
            }),
            page: {
                get() {
                    return this.$store.state.sqVuex.page
                },
                set(val) {
                    this.$store.commit('sqVuex/SET_PAGE', val)
                }
            }
        },
        filters: {
            currency: function(money) {
            return accounting.formatMoney(money, "Rp ", 2, ".", ",")
            }
        },
        watch: {
            page() {
                this.getListSalesQuot({
                    status: this.filter_status,
                    search: this.search
                })
            },
            search() {
                this.getListSalesQuot({
                    status: this.filter_status,
                    search: this.search
                })
            },
            filter_status() {
                this.getListSalesQuot({
                    status: this.filter_status,
                    search: this.search
                })
            }
        },
        methods: {
            ...mapActions('sqVuex', ['getListSalesQuot']) 
        }
    }
    </script>
    
  2. Редактировать. vue

    <template>
        <div class="col-md-12">
            <div class="panel">
                <div class="panel-heading">
                    <h3 class="panel-title">Add Sales Quotation</h3>
                </div>
                <div class="panel-body">
    
                    <salesQuot-form ref="salesQuotForm"></salesQuot-form>
                    <div class="form-group">
                        <button class="btn btn-primary btn-sm btn-flat" @click.prevent="submit">
                            <i class="fa fa-save"></i> Save
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </template>
    <script>
        import { mapActions, mapState, mapMutations } from 'vuex'
        import FormSalesQuot from './Form.vue'
        export default {
            name: 'AddSalesQuotation',
            methods: {
                submit() {
                    this.$refs.salesQuotForm.submit()
                }
            },
            components: {
                'salesQuot-form': FormSalesQuot
            }
        }
    </script>
    
  3. Detail. vue

    <template>
        <div class="col-md-12">
            <div class="panel">
                <div class="panel-body">
                    <div class="row">
    
                        <div class="col-md-6 table table-responsive-xl" >
    
                            <h4> <strong>Customer</strong> </h4>
                            <hr>
    
                            <v-select :options="customerData.data"
                                v-model="sq.customer"
                                @search="onSearch" 
                                label="cust_name"
                                placeholder="Search..." 
                                :filterable="false">
                                <template slot="no-options">
                                    Search Customer
                                </template>
                                <template slot="option" slot-scope="option">
                                    {{ option.cust_number }}:   {{ option.cust_name }}
                                </template>
                            </v-select>
                        </div>
    
    
                        <div class="col-md-6 table table-responsive-xl" v-if="sq.customer">
    
                            <h4> <strong>Customer Info</strong> </h4>
                            <hr>
                            <table class="table table-hover table-responsive-xl">
                                <tr>
                                    <th width="15%">Customer Number </th>
                                    <td width="2%">:</td>
                                    <td>{{ sq.customer.cust_number }}</td>
                                </tr>
                                <tr>
                                    <th>Name </th>
                                    <td>:</td>
                                    <td>{{ sq.customer.cust_name }}</td>
                                </tr>
                                <tr>
                                    <th>Main Address </th>
                                    <td>:</td>
                                    <td>{{ sq.customer.address1 }}</td>
                                </tr>
                                <tr>
                                    <th>Alt. Address </th>
                                    <td>:</td>
                                    <td>{{ sq.customer.address2 }}</td>
                                </tr>
                                <tr>
                                    <th>Phone </th>
                                    <td>:</td>
                                    <td>{{ sq.customer.phone }}</td>
                                </tr>
                                <tr>
                                    <th>Contact Person </th>
                                    <td>:</td>
                                    <td>{{ sq.customer.contact }}</td>
                                </tr>
                            </table>
                        </div>
    
                        <div class="col-md-6 form-group" :class="{ 'has-error': errors.desc }">
                            <textarea cols="3" rows="3" class="form-control" v-model="sq.desc"></textarea>
                            <p class="text-danger" v-if="errors.desc">{{ errors.desc[0] }}</p>
                        </div>
    
                        <div class="col-md-12" style="padding-top: 20px">
    
                            <h4><strong>Detail Transaction</strong> </h4>
                            <hr>
    
                            <button class="btn btn-warning btn-sm" style="margin-bottom: 10px" @click="addProduct">Tambah</button>
                            <div class="text-uppercase text-bold">id selected: {{ selected  }}</div>
    
                            <div class="table table-responsive-xl">
                                    <b-table-simple striped hover bordered responsive show-empty style="height:500px">
                                    <b-thead>
                                        <b-tr>
                                            <b-th>
                                                <label class="form-checkbox">
                                                    <input type="checkbox" v-model="selectAll" @click="select">
                                                    <i class="form-icon"></i>
                                                </label>
                                            </b-th>
    
                                            <b-th>ID</b-th>
                                            <b-th width="35%" id="min-width">Product</b-th>
                                            <b-th width="5%" id="min-width">Quantity</b-th>
                                            <b-th id="min-width">Price</b-th>
                                            <b-th id="min-width">Subtotal</b-th>
                                            <b-th id="min-width">Actions</b-th>
                                        </b-tr>
                                    </b-thead>
                                    <b-tbody>
                                        <b-tr v-for="(row, index) in sq.detailSQ" :key="index">                                             
    
                                            <b-td>
                                                <label class="form-checkbox">
                                                    <input type="checkbox" :value="row.id" v-model="selected" @change="unCheckAll">
                                                    <i class="form-icon"></i>
                                                </label>                                                    
                                            </b-td>
    
                                            <b-td>{{row.id}}</b-td>
    
                                            <b-td>
                                                    <v-select :options="productData.data"
                                                        v-model="row.product"
                                                        @search="onSearchProduct" 
                                                        label="item_name_alt"
                                                        placeholder="Search..." 
                                                        :filterable="false"
                                                        style="width:300px">
                                                        <template slot="no-options">
                                                            Search Product
                                                        </template>
    
                                                        <template slot="option" slot-scope="option">
                                                            {{ option.peloduk.item_number }}: {{ option.item_name_alt }}
                                                        </template>
    
                                                    </v-select>
                                            </b-td>
    
                                            <b-td>
                                                <div class="input-group">
                                                    <input type="number" v-model="row.quantity" class="form-control" @blur="calculate(index)" style="width:70px">
                                                    <span class="input-group-addon">{{ row.product != null && row.product.satuanunit.unit == row.product.satuanunit.unit ? row.product.satuanunit.unit:'Unit' }}</span>
                                                </div>                                                  
                                            </b-td>
    
                                            <b-td> 
                                                <div class='input-group'> 
                                                    <my-cur-input v-model="row.price" @blur="calculate(index)"></my-cur-input>
                                                </div>
                                            </b-td>
    
                                            <b-td> {{ row.subtotal | currency }}</b-td>
    
                                            <b-td>
                                                    <button class="btn btn-success btn-sm btn-block"  @click="isDone(row.id)">
                                                        <i class="fa fa-paper-plane-o"></i>
                                                    </button>
                                            </b-td>
                                        </b-tr>
                                    </b-tbody>
    
                                    <b-tfoot>
                                        <b-tr>
                                        <b-th id="total" colspan="5" class="text-right">Total :</b-th>
                                        <b-td>{{ total | currency }}</b-td>
                                        <b-td> <button class="btn btn-success btn-sm btn-block"  @click="isDoneAll(selected)">
                                                </button>
                                        </b-td>
                                        </b-tr>
                                    </b-tfoot>
                                    </b-table-simple>    
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
        import { mapActions, mapState, mapMutations } from 'vuex'
        import vSelect from 'vue-select'
        import 'vue-select/dist/vue-select.css'
        import {Money} from 'v-money'
        import _ from 'lodash'
        import axios from 'axios';
    
        export default {
    
            name: 'DetailSalesQuotation',
            created() {
                this.getDetailSalesQuot(this.$route.params.id).then((res) => {
                    this.sq = {
                        customer: res.data.customer,    
                        desc: res.data.description,
                        detailSQ: res.data.detail
                    }
                })
            },
            data() {
                return {
                    selectAll: false,
                    selected: [],
                    amount: 0, 
                    customer_change: false,
                    sq: {
                        customer_id: '',
                        detailSQ: [
                            { product: null, quantity: 1, price: 0, subtotal: 0 }
                        ]
                    },
    
                }
            },              
    
            watch: {
            },
            filters: {
                currency: function(money) {
                return accounting.formatMoney(money, "Rp ", 2, ".", ",")
                }
            },
            computed: {
                ...mapState(['errors']),
                ...mapState('sqVuex', {
    
                    detailSQForm: state => state.detail_sq,
                    customerData: state => state.custs,
                    productData: state => state.custitems,
    
                }),                 
    
                total() {
                    return _.sumBy(this.sq.detailSQ, function(o) {
                        return parseFloat(o.subtotal)
                    })
                }
            },
            methods: {
                ...mapMutations('sqVuex', ['SET_ID_UPDATE']),
                ...mapActions('sqVuex', ['getDetailSalesQuot','getCust', 'getProd', 'updateSalesQuot', 'insertProduct']),
                onSearch(search, loading) {
    
                    this.getCust({
                        search: search,
                        loading: loading
                    })
                },
    
                onSearchProduct(search, loading) {
    
                    this.getProd({
                        search: search,
                        loading: loading
                    })
                },
                addProduct() {
                        this.sq.detailSQ.push({ product: null, quantity: null, price: 0, subtotal: 0 })                     
                },   
    
                calculate(index) {
                    let data = this.sq.detailSQ[index]
                    if (data.product != null) {
                        data.price = data.price
                        data.subtotal = (parseFloat(data.price) * (parseFloat(data.quantity))).toFixed(2)
                    }
                },
                select() {
                    this.selected = [];
    
                    if (!this.selectAll) {
                        for (let i in this.sq.detailSQ) {
                            this.selected.push(this.sq.detailSQ[i].id);
                        }
                    }
                },
                unCheckAll(){
                    if(this.selected.length == this.sq.detailSQ.length){
                        this.selectAll = true;
                    }
                    else{
                        this.selectAll = false;
                    }
                },
    
    
                //this is the problem
                submit() {
                this.isSuccess = false
                    let filter = _.filter(this.sq.detailSQ, function(item) {
                        return item.product != null
                    })
                     if (filter.length > 0) {
                         Object.assign(this.sq, { id: this.$route.params.id })
                            axios.all([                            
                                this.updateSalesQuot(this.sq)
                            ])
                     }                     
                },
                //this is the problem
    
            },
            components: 
                {
                vSelect,
                Money
                }
        }
    
    </script>
    

Backend Laravel

Из-за ограничения символов, модель и коллекция здесь не включены

  1. SalesQuotationsController

    <?php
    
    namespace App\Http\Controllers\API;
    
    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use App\SalesQuotation;
    use App\SalesQuotationDetail;
    use DB;
    
    use App\Http\Resources\SalesQuotationCollection;
    
    class SalesQuotationsController extends Controller
    {
        public function index() 
        {
            $search = request()->q; 
            $user = request()->user();      
    
            $salesquot = SalesQuotation::with(['user', 'detail', 'customer'])->orderBy('created_at', 'DESC')
                ->whereHas('customer', function($q) use($search) {
                    $q->where('cust_name', 'LIKE', '%' . $search . '%');
                });
    
            if (in_array(request()->status, [0,1])) {
                $salesquot = $salesquot->where('status', request()->status);
            }           
    
            $salesquot = $salesquot->paginate(10);
            return new SalesQuotationCollection($salesquot);
        }
    
        public function store(Request $request)
        {                       
                    DB::beginTransaction();
                    try{                
    
                        $sqend = SalesQuotation::orderBy('created_at', 'DESC')->first();
                        if ( ! $sqend )
                            $sqnum = 0;
                        else 
                            $sqnum = substr($sqend->sq_number, 2);
                            $urutansqnum = 'SQ' . sprintf('%04d', intval($sqnum) + 1);
    
                        $piend = SalesQuotation::orderBy('created_at', 'DESC')->first();
                        if (! $piend)
                            $pinum = 0;
                        else
                            $pinum = substr($piend->proforma_invoice_number, 2);
                            $urutanpinum = 'PI' . sprintf('%04d', intval($pinum) + 1);              
    
                        $user = $request->user();
    
                        $salesquot = SalesQuotation::create([
                            'sq_number' => $urutansqnum,
                            'master_cust_id' => $request->customer_id['id'],
                            'user_id' => $user->id,
                            'amount' => 0,
                            'description' => $request->desc,
                            'proforma_invoice_number' => $urutanpinum,
                            'status' => 'open'
                        ]);
    
                        $amount = 0; 
                        foreach ($request->detailSQ as $row) {
    
                            if (!is_null($row['product'])) {                
    
                                    $subtotal = $row['price'] * $row['quantity'];
    
                                 try{
    
                                    SalesQuotationDetail::create([
                                        'sales_quotation_id' => $salesquot->id,
                                        'master_cust_id' => $request->customer_id['id'],
                                        'master_cust_item_id' => $row['product']['id'],
                                        'master_unit_id' => $row['product']['master_unit_id'],
                                        'quantity' => $row['quantity'],
                                        'price' => $row['price'],
                                        'subtotal' => $subtotal,
                                        'description' => $request->desc
                                    ]);
    
                                    $amount += $subtotal; 
                                }
                            }
    
                        $salesquot->update(['amount' => $amount]);
    
                        DB::commit();
                        return response()->json(['status' => 'success', 'data' => $salesquot]);
                    }
                    catch (\Exception $e){
                        DB::rollback(); 
                        return response()->json(['status' => 'error', 'data' => $e->getMessage()]);
                    }
    
        }
    
        public function update(Request $request, $id)
        {               
            DB::beginTransaction();
            try{
    
                $user = $request->user();
    
                $slsqt = SalesQuotation::find($id);
    
                $slsqt->update([
                    'master_cust_id' => $request->customer['id'],
                    'description' => $request->desc
                ]);
    
                $amount = 0;
    
                foreach ($request->detailSQ as $row) {
    
                    if (!is_null($row['product'])) {
                            $subtotal = $row['price'] * $row['quantity'];
                         try{
    
                            $sld = SalesQuotationDetail::find($row['id']);                          
                                    $sld->update([
    
                                        'master_cust_id' => $request->customer['id'],
                                        'master_cust_item_id' => $row['product']['id'],
                                        'master_unit_id' => $row['product']['master_unit_id'],
                                        'quantity' => $row['quantity'],
                                        'price' => $row['price'],
                                        'subtotal' => $subtotal,
                                        'description' => $request->desc
                                    ]);
    
                                    $amount += $subtotal; 
                        }
                    }
    
                $slsqt->update(['amount' => $amount]);       
    
                DB::commit();
                return response()->json(['status' => 'success', 'data' => $slsqt]);
            }
            catch (\Exception $e){
                DB::rollback();
                return response()->json(['status' => 'error', 'data' => $e->getMessage(), $sld]);
                // return response()->json(['status' => 'error', 'data' => $slsqt]);
            }
    
        }
    
        public function insertProduct(request $request)
        {
            DB::beginTransaction();
                    try{
    
                        $amount = 0; 
                        foreach ($request->detailSQ as $row) {
    
                            if (!is_null($row['product'])) {
                                    $subtotal = $row['price'] * $row['quantity'];               
                                 try{
    
                                    $sqd = SalesQuotationDetail::create([
                                        'sales_quotation_id' => $request->id,
                                        'master_cust_id' => $request->customer_id['id'],
                                        'master_cust_item_id' => $row['product']['id'],
                                        'master_unit_id' => $row['product']['master_unit_id'],
                                        'quantity' => $row['quantity'],
                                        'price' => $row['price'],
                                        'subtotal' => $subtotal,
                                        'description' => $request->desc
                                    ]);
    
                                    $amount += $subtotal; 
                                }
                            }
    
                        $salesquot->update(['amount' => $amount]);
    
                        DB::commit();
                        return response()->json(['status' => 'success', 'data' => $sqd]);
                    }
                    catch (\Exception $e){
                        DB::rollback(); 
                        return response()->json(['status' => 'error', 'data' => $e->getMessage()]);
                    }
        }
    
        public function edit($id)
        {
            $sq = SalesQuotation::with(['customer', 'detail', 'detail.product', 'detail.product.satuanunit', 'detail.satuanunit'])->find($id);
            return response()->json(['status' => 'success', 'data' => $sq]);
        }
    }
    

Скриншот базы данных

  1. SalesQuotations

Снимок экрана структуры данных SalesQuotations

Снимок экрана данных SalesQuotations

SalesQuotationsDetail

Снимок экрана структуры данных SalesQuotationsDetail

Снимок экрана SalesQuotationsDetail

Снимок экрана программы

  1. Форма списка Форма списка

  2. Форма транзакции Форма транзакции

  3. Продолжение формы транзакции Форма транзакции

...