Merged in feature/2020-06-04 (pull request #93)

Feature/2020 06 04
This commit is contained in:
Patrick Fic
2021-06-02 17:09:31 +00:00
38 changed files with 515 additions and 78 deletions

View File

@@ -26853,6 +26853,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>orderedby</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>quantity</name> <name>quantity</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -54,7 +54,7 @@ export default function AccountingPayablesTableComponent({
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln), sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ownr_ln" && state.sortedInfo.order, state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
return record.job.owner ? ( return record.job.owner ? (
<Link to={"/manage/owners/" + record.job.owner.id}> <Link to={"/manage/owners/" + record.job.owner.id}>

View File

@@ -1,3 +1,4 @@
import { Space } from "antd";
import React from "react"; import React from "react";
import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component";
@@ -5,20 +6,16 @@ import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container";
export default function ChatConversationTitle({ conversation }) { export default function ChatConversationTitle({ conversation }) {
return ( return (
<div> <Space flex>
<div className="imex-flex-row"> <PhoneNumberFormatter>
<ChatConversationTitleTags {conversation && conversation.phone_num}
jobConversations={ </PhoneNumberFormatter>
(conversation && conversation.job_conversations) || [] <ChatConversationTitleTags
} jobConversations={
/> (conversation && conversation.job_conversations) || []
<ChatTagRoContainer conversation={conversation || []} /> }
</div> />
<div className="imex-flex-row"> <ChatTagRoContainer conversation={conversation || []} />
<PhoneNumberFormatter> </Space>
{conversation && conversation.phone_num}
</PhoneNumberFormatter>
</div>
</div>
); );
} }

View File

@@ -1,5 +1,5 @@
import { CloseCircleOutlined, LoadingOutlined } from "@ant-design/icons"; import { CloseCircleOutlined, LoadingOutlined } from "@ant-design/icons";
import { Select, Empty } from "antd"; import { Select, Empty, Space } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -13,27 +13,27 @@ export default function ChatTagRoComponent({
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div> <Space flex>
<Select <div style={{ width: "15rem" }}>
showSearch <Select
autoFocus showSearch
style={{ autoFocus
width: 300, dropdownMatchSelectWidth
}} placeholder={t("general.labels.search")}
placeholder={t("general.labels.search")} filterOption={false}
filterOption={false} onSearch={handleSearch}
onSearch={handleSearch} onSelect={handleInsertTag}
onSelect={handleInsertTag} notFoundContent={loading ? <LoadingOutlined /> : <Empty />}
notFoundContent={loading ? <LoadingOutlined /> : <Empty />} >
> {roOptions.map((item, idx) => (
{roOptions.map((item, idx) => ( <Select.Option key={item.id || idx}>
<Select.Option key={item.id || idx}> {` ${item.ro_number || ""} | ${item.ownr_fn || ""} ${
{` ${item.ro_number || ""} | ${item.ownr_fn || ""} ${ item.ownr_ln || ""
item.ownr_ln || "" } ${item.ownr_co_nm || ""}`}
} ${item.ownr_co_nm || ""}`} </Select.Option>
</Select.Option> ))}
))} </Select>
</Select> </div>
{loading ? <LoadingOutlined /> : null} {loading ? <LoadingOutlined /> : null}
{loading ? ( {loading ? (
@@ -41,6 +41,6 @@ export default function ChatTagRoComponent({
) : ( ) : (
<CloseCircleOutlined onClick={() => setVisible(false)} /> <CloseCircleOutlined onClick={() => setVisible(false)} />
)} )}
</div> </Space>
); );
} }

View File

@@ -29,7 +29,7 @@ export default function JobDetailCardsNotesComponent({ loading, data }) {
bordered bordered
dataSource={data.notes} dataSource={data.notes}
renderItem={(item) => ( renderItem={(item) => (
<List.Item> <List.Item style={{ whiteSpace: "pre-line" }}>
{item.critical ? ( {item.critical ? (
<EyeInvisibleFilled style={{ margin: 4, color: "red" }} /> <EyeInvisibleFilled style={{ margin: 4, color: "red" }} />
) : null} ) : null}

View File

@@ -8,8 +8,8 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort, dateSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import DataLabel from "../data-label/data-label.component"; import DataLabel from "../data-label/data-label.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component"; import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
@@ -40,14 +40,14 @@ export function JobPayments({
}); });
const columns = [ const columns = [
{ {
title: t("payments.fields.created_at"), title: t("payments.fields.date"),
dataIndex: "created_at", dataIndex: "date",
key: "created_at", key: "date",
sorter: (a, b) => dateSort(a.date, b.date),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "created_at" && state.sortedInfo.order, state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
<DateTimeFormatter>{record.created_at}</DateTimeFormatter>
),
}, },
{ {
title: t("payments.fields.payer"), title: t("payments.fields.payer"),

View File

@@ -39,24 +39,20 @@ export default async function DuplicateJob(
line.manual_line = true; line.manual_line = true;
}); });
newJob.joblines = keepJobLines ? _tempLines : []; newJob.joblines = keepJobLines ? _tempLines : [];
newJob.job_totals = (
await Axios.post("/job/totals", {
job: newJob,
})
).data;
delete newJob.joblines; delete newJob.joblines;
newJob.joblines = keepJobLines ? { data: _tempLines } : null; newJob.joblines = keepJobLines ? { data: _tempLines } : null;
apolloClient const res2 = await apolloClient.mutate({
.mutate({ mutation: INSERT_NEW_JOB,
mutation: INSERT_NEW_JOB, variables: { job: [newJob] },
variables: { job: [newJob] }, });
}) await Axios.post("/job/totalsssu", {
.then((res2) => { id: res2.data.insert_jobs.returning[0].id,
if (completionCallback) });
completionCallback(res2.data.insert_jobs.returning[0].id);
}); if (completionCallback)
completionCallback(res2.data.insert_jobs.returning[0].id);
//insert the new job. call the callback with the returned ID when done. //insert the new job. call the callback with the returned ID when done.

View File

@@ -2,7 +2,7 @@ import { DetermineFileType } from "../documents-upload/documents-upload.utility"
export const GenerateSrcUrl = (value) => { export const GenerateSrcUrl = (value) => {
let extension = value.extension; let extension = value.extension;
if (extension && extension.includes("heic")) extension = "jpg"; if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType( return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
value.type value.type

View File

@@ -166,7 +166,6 @@ function JobsDocumentsComponent({
zIndex: "5", zIndex: "5",
}} }}
onClick={() => { onClick={() => {
console.log(`Clicked`);
const newWindow = window.open( const newWindow = window.open(
`${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`, `${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`,
"_blank", "_blank",

View File

@@ -57,6 +57,9 @@ export function JobNotesComponent({
dataIndex: "text", dataIndex: "text",
key: "text", key: "text",
ellipsis: true, ellipsis: true,
render: (text, record) => (
<span style={{ whiteSpace: "pre-line" }}>{text}</span>
),
}, },
{ {

View File

@@ -237,6 +237,11 @@ export function PartsOrderListTableComponent({
<DateFormatter>{record.deliver_by}</DateFormatter> <DateFormatter>{record.deliver_by}</DateFormatter>
), ),
}, },
{
title: t("parts_orders.fields.orderedby"),
dataIndex: "orderedby",
key: "orderedby",
},
{ {
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",
@@ -336,6 +341,7 @@ export function PartsOrderListTableComponent({
/> />
), ),
}, },
{ {
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",

View File

@@ -73,6 +73,7 @@ export default function PartsOrderModalComponent({
<Form.Item required={false} key={field.key}> <Form.Item required={false} key={field.key}>
<LayoutFormRow grow noDivider> <LayoutFormRow grow noDivider>
<Form.Item <Form.Item
span={8}
label={t("parts_orders.fields.line_desc")} label={t("parts_orders.fields.line_desc")}
key={`${index}line_desc`} key={`${index}line_desc`}
name={[field.name, "line_desc"]} name={[field.name, "line_desc"]}

View File

@@ -81,6 +81,7 @@ export function PartsOrderModalContainer({
po: [ po: [
{ {
...values, ...values,
orderedby: currentUser.email,
jobid: jobId, jobid: jobId,
user_email: currentUser.email, user_email: currentUser.email,
return: isReturn, return: isReturn,

View File

@@ -73,7 +73,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
order_date order_date
deliver_by deliver_by
return return
orderedby
parts_order_lines { parts_order_lines {
id id
act_price act_price

View File

@@ -565,6 +565,7 @@ export const GET_JOB_BY_PK = gql`
stripeid stripeid
transactionid transactionid
memo memo
date
} }
cccontracts { cccontracts {
id id

View File

@@ -1602,6 +1602,7 @@
"oem_partno": "Part #", "oem_partno": "Part #",
"order_date": "Order Date", "order_date": "Order Date",
"order_number": "Order Number", "order_number": "Order Number",
"orderedby": "Ordered By",
"quantity": "Qty.", "quantity": "Qty.",
"return": "Return", "return": "Return",
"status": "Status" "status": "Status"

View File

@@ -1602,6 +1602,7 @@
"oem_partno": "", "oem_partno": "",
"order_date": "", "order_date": "",
"order_number": "", "order_number": "",
"orderedby": "",
"quantity": "", "quantity": "",
"return": "", "return": "",
"status": "" "status": ""

View File

@@ -1602,6 +1602,7 @@
"oem_partno": "", "oem_partno": "",
"order_date": "", "order_date": "",
"order_number": "", "order_number": "",
"orderedby": "",
"quantity": "", "quantity": "",
"return": "", "return": "",
"status": "" "status": ""

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."conversations" DROP COLUMN "archived";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."conversations" ADD COLUMN "archived" boolean NOT NULL
DEFAULT false;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."parts_orders" DROP COLUMN "orderedby";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."parts_orders" ADD COLUMN "orderedby" text NULL;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: alter table "public"."parts_orders" drop constraint "parts_orders_orderedby_fkey";
type: run_sql

View File

@@ -0,0 +1,10 @@
- args:
cascade: false
read_only: false
sql: |-
alter table "public"."parts_orders"
add constraint "parts_orders_orderedby_fkey"
foreign key ("orderedby")
references "public"."users"
("email") on update set null on delete set null;
type: run_sql

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_insert_permission
- args:
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- return
- returnfrombill
- status
- updated_at
- user_email
- vendorid
set: {}
role: user
table:
name: parts_orders
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,38 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_insert_permission
- args:
permission:
check:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- orderedby
- return
- returnfrombill
- status
- updated_at
- user_email
- vendorid
set: {}
role: user
table:
name: parts_orders
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,38 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- return
- returnfrombill
- status
- updated_at
- user_email
- vendorid
computed_fields: []
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: parts_orders
schema: public
type: create_select_permission

View File

@@ -0,0 +1,39 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- orderedby
- return
- returnfrombill
- status
- updated_at
- user_email
- vendorid
computed_fields: []
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: parts_orders
schema: public
type: create_select_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_update_permission
- args:
permission:
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- returnfrombill
- status
- updated_at
- user_email
- vendorid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: parts_orders
schema: public
type: create_update_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: parts_orders
schema: public
type: drop_update_permission
- args:
permission:
columns:
- created_at
- deliver_by
- id
- jobid
- order_date
- order_number
- orderedby
- returnfrombill
- status
- updated_at
- user_email
- vendorid
filter:
job:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: parts_orders
schema: public
type: create_update_permission

View File

@@ -0,0 +1,30 @@
- args:
role: user
table:
name: conversations
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- phone_num
- created_at
- updated_at
- bodyshopid
- id
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: conversations
schema: public
type: create_select_permission

View File

@@ -0,0 +1,31 @@
- args:
role: user
table:
name: conversations
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- archived
- bodyshopid
- created_at
- id
- phone_num
- updated_at
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: conversations
schema: public
type: create_select_permission

View File

@@ -0,0 +1,29 @@
- args:
role: user
table:
name: conversations
schema: public
type: drop_update_permission
- args:
permission:
columns:
- phone_num
- created_at
- updated_at
- bodyshopid
- id
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: conversations
schema: public
type: create_update_permission

View File

@@ -0,0 +1,30 @@
- args:
role: user
table:
name: conversations
schema: public
type: drop_update_permission
- args:
permission:
columns:
- archived
- bodyshopid
- created_at
- id
- phone_num
- updated_at
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: conversations
schema: public
type: create_update_permission

View File

@@ -0,0 +1,12 @@
- args:
cascade: false
read_only: false
sql: |-
alter table "public"."exportlog" drop constraint "exportlog_billid_fkey",
add constraint "exportlog_billid_fkey"
foreign key ("billid")
references "public"."bills"
("id")
on update restrict
on delete restrict;
type: run_sql

View File

@@ -0,0 +1,10 @@
- args:
cascade: false
read_only: false
sql: |-
alter table "public"."exportlog" drop constraint "exportlog_billid_fkey",
add constraint "exportlog_billid_fkey"
foreign key ("billid")
references "public"."bills"
("id") on update cascade on delete cascade;
type: run_sql

View File

@@ -1114,11 +1114,12 @@ tables:
- role: user - role: user
permission: permission:
columns: columns:
- phone_num - archived
- created_at
- updated_at
- bodyshopid - bodyshopid
- created_at
- id - id
- phone_num
- updated_at
filter: filter:
bodyshop: bodyshop:
associations: associations:
@@ -1133,11 +1134,12 @@ tables:
- role: user - role: user
permission: permission:
columns: columns:
- phone_num - archived
- created_at
- updated_at
- bodyshopid - bodyshopid
- created_at
- id - id
- phone_num
- updated_at
filter: filter:
bodyshop: bodyshop:
associations: associations:
@@ -3622,6 +3624,7 @@ tables:
- jobid - jobid
- order_date - order_date
- order_number - order_number
- orderedby
- return - return
- returnfrombill - returnfrombill
- status - status
@@ -3638,6 +3641,7 @@ tables:
- jobid - jobid
- order_date - order_date
- order_number - order_number
- orderedby
- return - return
- returnfrombill - returnfrombill
- status - status
@@ -3664,6 +3668,7 @@ tables:
- jobid - jobid
- order_date - order_date
- order_number - order_number
- orderedby
- returnfrombill - returnfrombill
- status - status
- updated_at - updated_at

View File

@@ -265,11 +265,11 @@ function GenerateCostingData(job) {
acc.labor[laborProfitCenter].add(laborAmount); acc.labor[laborProfitCenter].add(laborAmount);
if (val.mod_lbr_ty === "LAR") { if (val.mod_lbr_ty === "LAR") {
if (!acc.labor[defaultProfits["MAPA"]]) if (!acc.parts[defaultProfits["MAPA"]])
acc.labor[defaultProfits["MAPA"]] = Dinero(); acc.parts[defaultProfits["MAPA"]] = Dinero();
materialsHours.mapaHrs += val.mod_lb_hrs || 0; materialsHours.mapaHrs += val.mod_lb_hrs || 0;
acc.labor[defaultProfits["MAPA"]] = acc.labor[ acc.parts[defaultProfits["MAPA"]] = acc.parts[
defaultProfits["MAPA"] defaultProfits["MAPA"]
].add( ].add(
Dinero({ Dinero({
@@ -277,11 +277,11 @@ function GenerateCostingData(job) {
}).multiply(val.mod_lb_hrs || 0) }).multiply(val.mod_lb_hrs || 0)
); );
} }
if (!acc.labor[defaultProfits["MASH"]]) if (!acc.parts[defaultProfits["MASH"]])
acc.labor[defaultProfits["MASH"]] = Dinero(); acc.parts[defaultProfits["MASH"]] = Dinero();
if (val.mod_lbr_ty !== "LAR") { if (val.mod_lbr_ty !== "LAR") {
acc.labor[defaultProfits["MASH"]] = acc.labor[ acc.parts[defaultProfits["MASH"]] = acc.parts[
defaultProfits["MASH"] defaultProfits["MASH"]
].add( ].add(
Dinero({ Dinero({
@@ -402,6 +402,7 @@ function GenerateCostingData(job) {
}).multiply(materialsHours.mapaHrs) }).multiply(materialsHours.mapaHrs)
); );
} }
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mash) { if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mash) {
if ( if (
!billTotalsByCostCenters[ !billTotalsByCostCenters[