AdminInvoiceShow.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <template>
  2. <div class="AdminInvoiceShow"
  3. :style="localOptions.style">
  4. <div class="title q-pb-lg">
  5. <div class="static-title" />
  6. <div class="dynamic-title" />
  7. <div v-if="localOptions.showBackBtn"
  8. class="back-action">
  9. <q-btn flat
  10. :to="{name: 'Admin.Invoice.List'}"
  11. color="grey">
  12. بازگشت
  13. >
  14. </q-btn>
  15. </div>
  16. </div>
  17. <q-card v-if="invoice.item_info"
  18. class="q-mt-lg">
  19. <q-linear-progress v-if="invoice.loading"
  20. indeterminate />
  21. <q-card-section class="invoiceActionRow">
  22. <div class="heading">
  23. صورتحساب شناسه
  24. {{ invoice.id }}
  25. </div>
  26. <q-btn v-if="invoice.status==='PAYING'"
  27. outline
  28. color="primary"
  29. @click="onCancel()">
  30. لغو صورتحساب
  31. </q-btn>
  32. </q-card-section>
  33. <q-separator />
  34. <q-card-section>
  35. <q-banner>
  36. مشخصات خریدار
  37. </q-banner>
  38. <div class="row q-mt-md">
  39. <div class="col-md-3 col-12">
  40. نام و نام خانوادگی:
  41. {{ invoice.owner_info?.firstname }}
  42. {{ invoice.owner_info?.lastname }}
  43. </div>
  44. <div class="col-md-3 col-12">
  45. کد ملی:
  46. {{ invoice.owner_info?.national_code }}
  47. </div>
  48. <div class="col-md-3 col-12">
  49. تلفن همراه:
  50. {{ invoice.owner_info?.mobile_number }}
  51. </div>
  52. <div v-if="invoice.owner_info?.id"
  53. class="col-md-3 col-12">
  54. <q-btn outline
  55. color="primary"
  56. :to="{name: 'Admin.User.Show', params: {id: invoice.owner_info.id}}">
  57. مشخصات کاربر
  58. </q-btn>
  59. </div>
  60. </div>
  61. </q-card-section>
  62. <q-separator />
  63. <q-card-section>
  64. <div class="row">
  65. <div class="col-md-3 col-12">
  66. <q-banner>
  67. <q-icon name="isax:stickynote" />
  68. {{ getDateTime(invoice.creation_time) }}
  69. </q-banner>
  70. </div>
  71. <div class="col-md-3 col-12">
  72. <q-banner>
  73. {{ (invoice.amount ? invoice.amount.toLocaleString('fa') : 0) }}
  74. ریال
  75. </q-banner>
  76. </div>
  77. <div class="col-md-3 col-12">
  78. <q-banner>
  79. شماره پیگیری
  80. {{ invoice.id }}
  81. </q-banner>
  82. </div>
  83. <div class="col-md-3 col-12">
  84. <q-banner>
  85. وضعیت:
  86. {{ invoice.status_info.label }}
  87. </q-banner>
  88. </div>
  89. </div>
  90. </q-card-section>
  91. <q-separator />
  92. <q-card-section>
  93. <div class="row">
  94. <div v-if="invoice.item_type==='CLASSROOM'"
  95. class="col-md-4 col-12 flex items-center justify-start">
  96. <q-img :src="invoice.item_info.thumbnail"
  97. width="100px" />
  98. {{ invoice.item_info.title }}
  99. </div>
  100. <div v-else
  101. class="col-md-4 col-12 flex items-center justify-start">
  102. {{ invoice.title }}
  103. </div>
  104. <div v-if="invoice.item_type==='CLASSROOM'"
  105. class="col-md-4 col-12">
  106. <q-icon name="isax:user" />
  107. استاد:
  108. {{ invoice.item_info.professor_info.firstname }}
  109. {{ invoice.item_info.professor_info.lastname }}
  110. </div>
  111. <div v-else-if="invoice.item_type==='STORE_BASKET'"
  112. class="col-md-4 col-12">
  113. <q-icon name="isax:user" />
  114. کد سفارش:
  115. {{ invoice.item_info.id }}
  116. </div>
  117. <div class="col-md-4 col-12">
  118. <q-icon name="isax:card" />
  119. قیمت:
  120. {{ invoice.item_info?.price ? invoice.item_info.price.toLocaleString('fa') : 0 }}
  121. ریال
  122. </div>
  123. </div>
  124. </q-card-section>
  125. </q-card>
  126. <div class="action q-mt-lg">
  127. <q-card>
  128. <q-card-section>
  129. پرداخت
  130. </q-card-section>
  131. <q-separator />
  132. <q-card-section>
  133. <invoice-payment-card v-if="!invoice.loading && invoice.status!=='PAID_FULL'"
  134. :wallet="wallet"
  135. :invoice="invoice"
  136. :show-invoice-link="false"
  137. :show-timer="false"
  138. :show-message="false"
  139. :show-wallet="false"
  140. :can-action="false"
  141. class="payment-card"
  142. @onCancel="onCancel"
  143. @onAccept="onAccept"
  144. @onInstalmentPayed="onInstalmentPayed" />
  145. </q-card-section>
  146. </q-card>
  147. </div>
  148. <div v-if="invoice.item_type==='STORE_BASKET'"
  149. class="q-mt-md">
  150. <entity-index v-model:value="tableInputs"
  151. title="لیست محصولات سفارش"
  152. :table="table"
  153. :loaded-data="invoice.item_info"
  154. :table-keys="tableKeys"
  155. :show-search-button="false"
  156. :show-expand-button="false"
  157. :show-reload-button="false">
  158. <template #entity-index-table-cell="{inputData}">
  159. <template v-if="inputData.col.name === 'number'">
  160. {{ inputData.rowNumber }}
  161. </template>
  162. <template v-else-if="inputData.col.name === 'thumbnail'">
  163. <q-img :src="inputData.col.value"
  164. width="100px" />
  165. </template>
  166. <template v-else-if="inputData.col.name === 'download'">
  167. <q-btn v-if="!inputData.col.value"
  168. color="primary"
  169. @click="openDownloadDialog(inputData.props.row)">
  170. <q-icon name="download"
  171. class="q-mr-sm" />
  172. دانلود
  173. </q-btn>
  174. <template v-else>
  175. {{}}
  176. </template>
  177. </template>
  178. <template v-else-if="inputData.col.name === 'action'">
  179. <q-btn color="primary"
  180. outline
  181. :to="{name: inputData.props.row.product ? 'Admin.Store.Product.Show' : 'Admin.Store.Package.Show', params: {id: inputData.props.row.product || inputData.props.row.package}}">
  182. <q-icon name="visibility"
  183. class="q-mr-sm" />
  184. مشاهده
  185. </q-btn>
  186. </template>
  187. <template v-else>
  188. {{ inputData.col.value }}
  189. </template>
  190. </template>
  191. </entity-index>
  192. <q-dialog v-model="downloadDialog">
  193. <q-card style="width: 800px; max-width: 95%;">
  194. <q-card-section>
  195. محتوای قابل دانلود
  196. </q-card-section>
  197. <q-separator />
  198. <q-card-section>
  199. <product-or-package-medias :basket-item="selectedBasketItem" />
  200. </q-card-section>
  201. </q-card>
  202. </q-dialog>
  203. </div>
  204. </div>
  205. </template>
  206. <script>
  207. import Assist from 'assets/js/Assist.js'
  208. import { User } from 'src/models/User.js'
  209. import { EntityIndex } from 'quasar-crud'
  210. import { Wallet } from 'src/models/Wallet.js'
  211. import { Product } from 'src/models/Product.js'
  212. import { Invoice } from 'src/models/Invoice.js'
  213. import { mixinWidget } from 'src/mixin/Mixins.js'
  214. import { APIGateway } from 'src/api/APIGateway.js'
  215. import InvoicePaymentCard from 'src/components/InvoicePaymentCard/InvoicePaymentCard.vue'
  216. import ProductOrPackageMedias from 'src/components/Widgets/Store/Basket/UserStoreBasketShow/ProductOrPackageMedias.vue'
  217. export default {
  218. name: 'AdminInvoiceShow',
  219. components: { InvoicePaymentCard, EntityIndex, ProductOrPackageMedias },
  220. mixins: [mixinWidget],
  221. props: {
  222. invoiceId: {
  223. type: Number,
  224. default: null
  225. }
  226. },
  227. data () {
  228. return {
  229. user: new User(),
  230. wallet: new Wallet(),
  231. invoice: new Invoice(),
  232. defaultOptions: {
  233. showBackBtn: true
  234. },
  235. downloadDialog: false,
  236. selectedBasketItem: null,
  237. tableKeys: {
  238. data: 'items_info.list',
  239. total: 'count',
  240. currentPage: 'current',
  241. perPage: 'per_page',
  242. pageKey: 'page'
  243. },
  244. tableInputs: [],
  245. table: {
  246. columns: [
  247. {
  248. name: 'number',
  249. required: true,
  250. label: 'شماره',
  251. align: 'left',
  252. field: () => ''
  253. },
  254. {
  255. name: 'id',
  256. required: true,
  257. label: 'شناسه',
  258. align: 'left',
  259. field: row => row.product_info?.id ? row.product_info.id : row.package_info.id
  260. },
  261. {
  262. name: 'title',
  263. required: true,
  264. label: 'نام محصول',
  265. align: 'left',
  266. field: row => (row.product_info?.id ? row.product_info : row.package_info).title
  267. },
  268. {
  269. name: 'is_package_or_product',
  270. required: true,
  271. label: 'نوع محصول',
  272. align: 'left',
  273. field: row => row.package ? 'بسته' : 'تکی'
  274. },
  275. {
  276. name: 'store_category',
  277. required: true,
  278. label: 'دسته فروشگاه',
  279. align: 'left',
  280. field: row => ((row.product_info?.id ? row.product_info : row.package_info).store_category_info?.parent?.parent?.title || '-') + '، ' + ((row.product_info || row.package_info).store_category_info?.parent?.title || '-') + '، ' + ((row.product_info || row.package_info).store_category_info?.title || '-')
  281. },
  282. {
  283. name: 'store_category1',
  284. required: true,
  285. label: 'دسته محتوا',
  286. align: 'left',
  287. field: row => ((row.product_info?.id ? row.product_info : row.package_info).content_category_info?.parent?.parent?.title || '-') + '، ' + ((row.product_info || row.package_info).content_category_info?.parent?.title || '-') + '، ' + ((row.product_info || row.package_info).content_category_info?.title || '-')
  288. },
  289. {
  290. name: 'count',
  291. required: true,
  292. label: 'تعداد',
  293. align: 'left',
  294. field: row => row.count
  295. },
  296. {
  297. name: 'is_physical_info',
  298. required: true,
  299. label: 'نوع جنس',
  300. align: 'left',
  301. field: row => (row.product_info?.id ? row.product_info : row.package_info).is_physical_info.label
  302. },
  303. {
  304. name: 'physical_type_info',
  305. required: true,
  306. label: 'نوع محصول',
  307. align: 'left',
  308. field: row => row.product_info ? (new Product(row.product_info)).physical_type_info.label : '-'
  309. },
  310. {
  311. name: 'unit_price',
  312. required: true,
  313. label: 'قیمت',
  314. align: 'left',
  315. field: row => parseInt((row.product_info?.id ? row.product_info : row.package_info).unit_price?.toString()).toLocaleString('fa')
  316. },
  317. {
  318. name: 'download',
  319. required: true,
  320. label: 'دانلود',
  321. align: 'left',
  322. field: row => (row.product_info?.id ? row.product_info : row.package_info).is_physical
  323. },
  324. {
  325. name: 'action',
  326. required: true,
  327. label: 'عملیات',
  328. align: 'left',
  329. field: row => ''
  330. }
  331. ]
  332. }
  333. }
  334. },
  335. mounted() {
  336. this.loadAuthData()
  337. this.getMyWallet()
  338. this.getInvoice()
  339. },
  340. methods: {
  341. openDownloadDialog (basketItem) {
  342. this.selectedBasketItem = basketItem
  343. this.downloadDialog = true
  344. },
  345. loadAuthData() { // prevent Hydration node mismatch
  346. this.user = this.$store.getters['Auth/user']
  347. },
  348. getDateTime (dateTime) {
  349. return Assist.miladiToShamsi(dateTime)
  350. },
  351. onCancel () {
  352. this.invoice.loading = true
  353. APIGateway.invoice.cancel(this.invoice.id)
  354. .then((message) => {
  355. this.invoice.loading = false
  356. this.getInvoice()
  357. this.$q.notify({
  358. message,
  359. type: 'positive'
  360. })
  361. })
  362. .catch(() => {
  363. this.invoice.loading = false
  364. })
  365. },
  366. onAccept () {
  367. this.payInvoice()
  368. },
  369. onInstalmentPayed () {
  370. this.getMyWallet()
  371. this.getInvoice()
  372. },
  373. getMyWallet () {
  374. this.wallet.loading = true
  375. APIGateway.wallet.getMyWallet(this.user.id)
  376. .then((wallet) => {
  377. this.wallet = new Wallet(wallet)
  378. this.wallet.loading = false
  379. this.walletLoaded = true
  380. })
  381. .catch(() => {
  382. this.wallet.loading = false
  383. })
  384. },
  385. amountOfDepositWalletNeeded () {
  386. return this.invoice.amount - this.wallet.inventory
  387. },
  388. payInvoice () {
  389. if (this.amountOfDepositWalletNeeded() > 0) {
  390. this.payInvoiceByDepositWallet()
  391. } else {
  392. this.payInvoiceByWallet()
  393. }
  394. },
  395. payInvoiceByWallet () {
  396. this.invoice.loading = true
  397. APIGateway.invoice.pay(this.invoice.id)
  398. .then((message) => {
  399. this.invoice.loading = false
  400. this.getInvoice()
  401. this.$q.notify({
  402. message,
  403. type: 'positive'
  404. })
  405. })
  406. .catch(() => {
  407. this.invoice.loading = false
  408. })
  409. },
  410. payInvoiceByDepositWallet () {
  411. this.invoice.loading = true
  412. APIGateway.wallet.deposit({
  413. amount: this.amountOfDepositWalletNeeded(),
  414. invoice: this.invoice.id
  415. })
  416. .then((url) => {
  417. window.location.href = url
  418. })
  419. .catch(() => {
  420. this.depositLoading = false
  421. })
  422. },
  423. getInvoiceId () {
  424. return this.localOptions.invoiceId || this.$route.params.id
  425. },
  426. getInvoice () {
  427. this.invoice.loading = true
  428. const invoiceId = this.getInvoiceId()
  429. APIGateway.invoice.get({ data: { id: invoiceId } })
  430. .then((invoice) => {
  431. this.invoice = new Invoice(invoice)
  432. this.invoice.loading = false
  433. })
  434. .catch(() => {
  435. this.invoice.loading = false
  436. })
  437. }
  438. }
  439. }
  440. </script>
  441. <style scoped lang="scss">
  442. .AdminInvoiceShow {
  443. .title {
  444. font-style: normal;
  445. font-weight: 700;
  446. font-size: 24px;
  447. line-height: 140%;
  448. color: #424242;
  449. margin-bottom: 27px;
  450. display: flex;
  451. flex-flow: row;
  452. position: relative;
  453. .static-title {
  454. }
  455. .dynamic-title {
  456. }
  457. .back-action {
  458. position: absolute;
  459. right: 0;
  460. top: 0;
  461. }
  462. }
  463. .invoiceActionRow {
  464. display: flex;
  465. flex-flow: row;
  466. justify-content: space-between;
  467. align-items: center;
  468. .heading {
  469. font-size: 18px;
  470. }
  471. }
  472. }
  473. </style>