Finish the majority of work on vendors page to add/delete/edit.

This commit is contained in:
Patrick Fic
2020-02-13 16:08:34 -08:00
parent d1b14427cc
commit 206c1e268b
12 changed files with 757 additions and 61 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project version="1.2" be_version="2.6.1">
<babeledit_project be_version="2.6.1" version="1.2">
<!--
BabelEdit project file
@@ -1487,6 +1487,27 @@
<folder_node>
<name>validation</name>
<children>
<concept_node>
<name>invalidemail</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>
<name>required</name>
<definition_loaded>false</definition_loaded>
@@ -6819,6 +6840,58 @@
<folder_node>
<name>vendors</name>
<children>
<folder_node>
<name>actions</name>
<children>
<concept_node>
<name>new</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>
</children>
</folder_node>
<folder_node>
<name>errors</name>
<children>
<concept_node>
<name>saving</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>
</children>
</folder_node>
<folder_node>
<name>fields</name>
<children>
@@ -6864,6 +6937,111 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>country</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>
<name>discount</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>
<name>display_name</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>
<name>due_date</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>
<name>email</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>
<name>favorite</name>
<definition_loaded>false</definition_loaded>
@@ -6906,6 +7084,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>prompt_discount</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>
<name>state</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>
<name>street1</name>
<definition_loaded>false</definition_loaded>
@@ -6927,6 +7147,163 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>street2</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>
<name>taxid</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>
<name>terms</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>
<name>zip</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>
</children>
</folder_node>
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>noneselected</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>
</children>
</folder_node>
<folder_node>
<name>successes</name>
<children>
<concept_node>
<name>deleted</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>
<name>saved</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>
</children>
</folder_node>
</children>

View File

@@ -1,11 +1,11 @@
import { Button, Form, Input, notification } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
import { Form, Input, notification, Button } from "antd";
import { updateUserDetails } from "../../redux/user/user.actions";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import ResetForm from "../form-items-formatted/reset-form-item.component";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
@@ -47,33 +47,26 @@ export default connect(
return (
<div>
{isFieldsTouched() ? (
//TODO: Appropriate Error
<AlertComponent
message={t("jobs.errors.validation")}
onClick={() => resetFields()}
/>
) : null}
{isFieldsTouched() ? <ResetForm resetFields={resetFields} /> : null}
<Form onSubmit={handleSubmit} autoComplete={"no"}>
<Form.Item label={t("user.fields.displayname")}>
{getFieldDecorator("displayname", {
initialValue: currentUser.displayName,
rules: [{ required: true }]
})(<Input name="displayname" />)}
})(<Input name='displayname' />)}
</Form.Item>
<Form.Item label={t("user.fields.photourl")}>
{getFieldDecorator("photoURL", {
initialValue: currentUser.photoURL
})(<Input name="photoURL" />)}
})(<Input name='photoURL' />)}
</Form.Item>
<Button
type="primary"
key="submit"
htmlType="submit"
onClick={handleSubmit}
>
type='primary'
key='submit'
htmlType='submit'
onClick={handleSubmit}>
{t("user.actions.updateprofile")}
</Button>
</Form>

View File

@@ -0,0 +1,114 @@
import { Button, Form, Input, InputNumber, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import ResetForm from "../form-items-formatted/reset-form-item.component";
export default function VendorsFormComponent({ form, vendor, handleDelete }) {
const {
getFieldDecorator,
isFieldsTouched,
getFieldValue,
resetFields
} = form;
const { t } = useTranslation();
return (
<div>
{isFieldsTouched() ? <ResetForm resetFields={resetFields} /> : null}
<Button htmlType='submit' type='primary'>
{t("general.actions.save")}
</Button>
<Button type='danger' onClick={handleDelete}>
{t("general.actions.delete")}
</Button>
<Form.Item label={t("vendors.fields.zip")}>
{getFieldDecorator("zip", {
initialValue: vendor.zip
})(<Input name='zip' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.terms")}>
{getFieldDecorator("terms", {
initialValue: vendor.terms
})(<Input name='terms' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.taxid")}>
{getFieldDecorator("taxid", {
initialValue: vendor.taxid
})(<Input name='taxid' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.street1")}>
{getFieldDecorator("street1", {
initialValue: vendor.street1
})(<Input name='street1' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.street2")}>
{getFieldDecorator("street2", {
initialValue: vendor.street2
})(<Input name='street2' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.state")}>
{getFieldDecorator("state", {
initialValue: vendor.state
})(<Input name='state' />)}
</Form.Item>{" "}
<Form.Item label={t("vendors.fields.prompt_discount")}>
{getFieldDecorator("prompt_discount", {
initialValue: vendor.prompt_discount
})(<InputNumber name='prompt_discount' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.name")}>
{getFieldDecorator("name", {
initialValue: vendor.name
})(<Input name='name' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.favorite")}>
{getFieldDecorator("favorite", {
initialValue: vendor.favorite,
valuePropName: "checked"
})(<Switch name='favorite' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.email")}>
{getFieldDecorator("email", {
initialValue: vendor.email,
rules: [
{
type: "email",
message: t("general.validation.invalidemail")
}
]
})(<FormItemEmail name='email' email={getFieldValue("email")} />)}
</Form.Item>
<Form.Item label={t("vendors.fields.due_date")}>
{getFieldDecorator("due_date", {
initialValue: vendor.due_date
})(<InputNumber name='due_date' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.display_name")}>
{getFieldDecorator("display_name", {
initialValue: vendor.display_name
})(<Input name='display_name' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.discount")}>
{getFieldDecorator("discount", {
initialValue: vendor.discount
})(<InputNumber name='discount' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.country")}>
{getFieldDecorator("country", {
initialValue: vendor.country
})(<Input name='country' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.cost_center")}>
{getFieldDecorator("cost_center", {
initialValue: vendor.cost_center,
rules: [{ required: true, message: t("general.validation.required") }]
})(<Input name='cost_center' />)}
</Form.Item>
<Form.Item label={t("vendors.fields.city")}>
{getFieldDecorator("city", {
initialValue: vendor.city
})(<Input name='city' />)}
</Form.Item>
</div>
);
}

View File

@@ -0,0 +1,109 @@
import React from "react";
import { Form } from "antd";
import VendorsFormComponent from "./vendors-form.component";
import { useTranslation } from "react-i18next";
import { notification } from "antd";
import {
UPDATE_VENDOR,
INSERT_NEW_VENDOR,
DELETE_VENDOR
} from "../../graphql/vendors.queries";
import { useMutation } from "react-apollo";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
function VendorsFormContainer({ form, vendor, refetch, bodyshop }) {
const { t } = useTranslation();
const [updateVendor] = useMutation(UPDATE_VENDOR);
const [insertvendor] = useMutation(INSERT_NEW_VENDOR);
const [deleteVendor] = useMutation(DELETE_VENDOR);
const handleDelete = () => {
deleteVendor({ variables: { id: vendor.id } })
.then(r => {
notification["success"]({
message: t("vendors.successes.deleted")
});
//TODO: Better way to reset the field decorators?
if (refetch) refetch().then(r => form.resetFields());
})
.catch(error => {
notification["error"]({
message: t("vendors.errors.deleting")
});
});
};
const handleSubmit = e => {
e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
if (err) {
notification["error"]({
message: t("jobs.errors.validationtitle"),
description: t("jobs.errors.validation")
});
}
if (!err) {
if (vendor.id) {
//It's a vendor to update.
updateVendor({
variables: { id: vendor.id, vendor: values }
})
.then(r => {
notification["success"]({
message: t("vendors.successes.saved")
});
//TODO: Better way to reset the field decorators?
if (refetch) refetch().then(r => form.resetFields());
})
.catch(error => {
notification["error"]({
message: t("vendors.errors.saving")
});
});
} else {
//It's a new vendor to insert.
insertvendor({
variables: { vendorInput: [{ ...values, bodyshopid: bodyshop.id }] }
})
.then(r => {
notification["success"]({
message: t("vendors.successes.saved")
});
//TODO: Better way to reset the field decorators?
if (refetch) refetch().then(r => form.resetFields());
})
.catch(error => {
notification["error"]({
message: t("vendors.errors.saving")
});
});
}
}
});
};
return (
<div>
<Form onSubmit={handleSubmit} autoComplete='new-password'>
{vendor ? (
<VendorsFormComponent
form={form}
vendor={vendor}
handleDelete={handleDelete}
/>
) : (
t("vendors.labels.noneselected")
)}
</Form>
</div>
);
}
export default connect(
mapStateToProps,
null
)(Form.create({ name: "VendorsFormContainer" })(VendorsFormContainer));

View File

@@ -1,12 +1,14 @@
import { Input, Table } from "antd";
import { Input, Table, Button } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters";
export default function VendorsListComponent({
selectedVendor,
setSelectedVendor,
handleNewVendor,
loading,
refetch,
handleOnRowClick,
vendors
}) {
const [state, setState] = useState({
@@ -57,14 +59,6 @@ export default function VendorsListComponent({
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const handleOnRowClick = record => {
if (record) {
setSelectedVendor(record);
return;
}
setSelectedVendor(null);
};
//TODO Implement search
return (
<div>
@@ -72,19 +66,25 @@ export default function VendorsListComponent({
loading={loading}
title={() => {
return (
<Input.Search
placeholder={t("general.labels.search")}
onSearch={value => {
console.log(value);
}}
enterButton
/>
<div>
{" "}
<Input.Search
placeholder={t("general.labels.search")}
onSearch={value => {
console.log(value);
}}
enterButton
/>
<Button onClick={handleNewVendor}>
{t("vendors.actions.new")}
</Button>
</div>
);
}}
size="small"
size='small'
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
rowKey='id'
onChange={handleTableChange}
dataSource={vendors}
rowSelection={{
@@ -92,7 +92,7 @@ export default function VendorsListComponent({
setSelectedVendor(record);
},
type: "radio",
selectedRowKeys: selectedVendor.id || null
selectedRowKeys: selectedVendor ? selectedVendor.id : null
}}
onRow={(record, rowIndex) => {
return {

View File

@@ -1,7 +1,7 @@
import React from "react";
import { useQuery } from "react-apollo";
import AlertComponent from "../../components/alert/alert.component";
import { QUERY_ALL_VENDORS, QUERY_VENDOR_BY_ID } from "../../graphql/vendors.queries";
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
import VendorsListComponent from "./vendors-list.component";
export default function VendorsListContainer({ selectedVendorState }) {
@@ -10,23 +10,28 @@ export default function VendorsListContainer({ selectedVendorState }) {
fetchPolicy: "network-only"
});
const vendorDetail = useQuery(QUERY_VENDOR_BY_ID, {
fetchPolicy: "network-only",
variables: { id: selectedVendor.id },
skip: !selectedVendor.id
});
const handleNewVendor = () => {
setSelectedVendor({});
};
if (error) return <AlertComponent message={error.message} type="error" />;
const handleOnRowClick = record => {
if (record) {
setSelectedVendor(record);
return;
}
setSelectedVendor(null);
};
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<div>
<VendorsListComponent
selectedVendor={selectedVendor}
setSelectedVendor={setSelectedVendor}
loading={loading}
refetch={refetch}
vendors={data ? data.vendors : null}
/>
{JSON.stringify(vendorDetail && vendorDetail.data)}
</div>
<VendorsListComponent
selectedVendor={selectedVendor}
setSelectedVendor={setSelectedVendor}
handleNewVendor={handleNewVendor}
handleOnRowClick={handleOnRowClick}
loading={loading}
refetch={refetch}
vendors={data ? data.vendors : null}
/>
);
}

View File

@@ -24,9 +24,9 @@ export const QUERY_VENDOR_BY_ID = gql`
}
`;
export const UPDATE_VEHICLE = gql`
mutation UPDATE_VEHICLE($vehId: uuid!, $vehicle: vehicles_set_input!) {
update_vehicles(where: { id: { _eq: $vehId } }, _set: $vehicle) {
export const UPDATE_VENDOR = gql`
mutation UPDATE_VENDOR($id: uuid!, $vendor: vendors_set_input!) {
update_vendors(where: { id: { _eq: $id } }, _set: $vendor) {
returning {
id
}
@@ -46,3 +46,23 @@ export const QUERY_ALL_VENDORS = gql`
}
}
`;
export const INSERT_NEW_VENDOR = gql`
mutation INSERT_NEW_VENDOR($vendorInput: [vendors_insert_input!]!) {
insert_vendors(objects: $vendorInput) {
returning {
id
}
}
}
`;
export const DELETE_VENDOR = gql`
mutation DELETE_VENDOR($id: uuid!) {
delete_vendors(where: { id: { _eq: $id } }) {
returning {
id
}
}
}
`;

View File

@@ -1,10 +1,13 @@
import React from "react";
import VendorsListContainer from "../../components/vendors-list/vendors-list.container";
import VendorsFormContainer from "../../components/vendors-form/vendors-form.container";
export default function ShopVendorPageComponent({ selectedVendorState }) {
//TODO Figure out how to handle the refresh list when saving form
return (
<div>
<VendorsListContainer selectedVendorState={selectedVendorState} />
<VendorsFormContainer vendor={selectedVendorState[0]} />
</div>
);
}

View File

@@ -8,7 +8,7 @@ export default function ShopVendorPageContainer() {
document.title = t("titles.shop_vendors");
}, [t]);
const selectedVendorState = useState({});
const selectedVendorState = useState();
return (
<div>
<ShopVendorPageComponent selectedVendorState={selectedVendorState} />

View File

@@ -121,6 +121,7 @@
"unsavedchanges": "You have unsaved changes."
},
"validation": {
"invalidemail": "Please enter a valid email.",
"required": "This field is required. "
}
},
@@ -441,12 +442,36 @@
}
},
"vendors": {
"actions": {
"new": "New Vendor"
},
"errors": {
"saving": "Error encountered while saving vendor. "
},
"fields": {
"city": "City",
"cost_center": "Cost Center",
"country": "Country",
"discount": "Discount %",
"display_name": "Display Name",
"due_date": "Payment Due Date",
"email": "Contact Email",
"favorite": "Favorite?",
"name": "Vendor Name",
"street1": "Street"
"prompt_discount": "Prompt Discount %",
"state": "State/Province",
"street1": "Street",
"street2": "Address 2",
"taxid": "Tax ID",
"terms": "Payment Terms",
"zip": "Zip/Postal Code"
},
"labels": {
"noneselected": "No vendor is selected."
},
"successes": {
"deleted": "Vendor deleted successfully. ",
"saved": "Vendor saved successfully."
}
}
}

View File

@@ -121,6 +121,7 @@
"unsavedchanges": "Usted tiene cambios no guardados."
},
"validation": {
"invalidemail": "Por favor introduzca una dirección de correo electrónico válida.",
"required": "Este campo es requerido."
}
},
@@ -441,12 +442,36 @@
}
},
"vendors": {
"actions": {
"new": "Nuevo vendedor"
},
"errors": {
"saving": "Se encontró un error al guardar el proveedor."
},
"fields": {
"city": "ciudad",
"cost_center": "Centro de costos",
"country": "País",
"discount": "% De descuento",
"display_name": "Nombre para mostrar",
"due_date": "Fecha de vencimiento del pago",
"email": "Email de contacto",
"favorite": "¿Favorito?",
"name": "Nombre del vendedor",
"street1": "calle"
"prompt_discount": "Descuento pronto",
"state": "Provincia del estado",
"street1": "calle",
"street2": "Dirección 2",
"taxid": "Identificación del impuesto",
"terms": "Términos de pago",
"zip": "código postal"
},
"labels": {
"noneselected": "Ningún vendedor está seleccionado."
},
"successes": {
"deleted": "Proveedor eliminado correctamente.",
"saved": "Proveedor guardado con éxito."
}
}
}

View File

@@ -121,6 +121,7 @@
"unsavedchanges": "Vous avez des changements non enregistrés."
},
"validation": {
"invalidemail": "S'il vous plaît entrer un email valide.",
"required": "Ce champ est requis."
}
},
@@ -441,12 +442,36 @@
}
},
"vendors": {
"actions": {
"new": "Nouveau vendeur"
},
"errors": {
"saving": "Erreur rencontrée lors de l'enregistrement du fournisseur."
},
"fields": {
"city": "Ville",
"cost_center": "Centre de coûts",
"country": "Pays",
"discount": "Remise %",
"display_name": "Afficher un nom",
"due_date": "Date limite de paiement",
"email": "Email du contact",
"favorite": "Préféré?",
"name": "Nom du vendeur",
"street1": "rue"
"prompt_discount": "Remise rapide%",
"state": "Etat / Province",
"street1": "rue",
"street2": "Adresse 2 ",
"taxid": "Identifiant de taxe",
"terms": "Modalités de paiement",
"zip": "Zip / code postal"
},
"labels": {
"noneselected": "Aucun fournisseur n'est sélectionné."
},
"successes": {
"deleted": "Le fournisseur a bien été supprimé.",
"saved": "Le fournisseur a bien enregistré."
}
}
}