Skip to content
Snippets Groups Projects
Commit 7d0f5ee7 authored by meskio's avatar meskio :tent:
Browse files

Inventary UI

parent 8f7bd7ca
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,7 @@ type Inventary struct { ...@@ -17,7 +17,7 @@ type Inventary struct {
MemberNum int `json:"-" gorm:"column:member"` MemberNum int `json:"-" gorm:"column:member"`
Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"` Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
Date time.Time `json:"date"` Date time.Time `json:"date"`
SupplierID *uint `json:"-"` SupplierID *uint `json:"supplier_id"`
Supplier *Supplier `json:"supplier"` Supplier *Supplier `json:"supplier"`
Comment string `json:"comment"` Comment string `json:"comment"`
Products []InventaryProduct `json:"products"` Products []InventaryProduct `json:"products"`
......
...@@ -31,6 +31,31 @@ function Head(props) { ...@@ -31,6 +31,31 @@ function Head(props) {
</NavDropdown> </NavDropdown>
); );
} }
let productNav = (
<LinkContainer to="/products">
<Nav.Link>Productos</Nav.Link>
</LinkContainer>
);
if (auth.role === "admin") {
productNav = (
<NavDropdown title="Productos" id="admin">
<LinkContainer to="/products">
<NavDropdown.Item>Productos</NavDropdown.Item>
</LinkContainer>
<LinkContainer to="/inventary">
<NavDropdown.Item>Inventario</NavDropdown.Item>
</LinkContainer>
<LinkContainer to="/inventary/add">
<NavDropdown.Item>Entrada</NavDropdown.Item>
</LinkContainer>
<LinkContainer to="/supplier/add">
<NavDropdown.Item>Añade Proveedor</NavDropdown.Item>
</LinkContainer>
</NavDropdown>
);
}
return ( return (
<Navbar bg="light" expand="sm"> <Navbar bg="light" expand="sm">
<LinkContainer to="/"> <LinkContainer to="/">
...@@ -46,10 +71,8 @@ function Head(props) { ...@@ -46,10 +71,8 @@ function Head(props) {
</LinkContainer> </LinkContainer>
<Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav"> <Navbar.Collapse id="basic-navbar-nav">
{productNav}
<Nav className="mr-auto" activeKey={location.pathname}> <Nav className="mr-auto" activeKey={location.pathname}>
<LinkContainer to="/products">
<Nav.Link>Productos</Nav.Link>
</LinkContainer>
<LinkContainer to="/purchase"> <LinkContainer to="/purchase">
<Nav.Link>Comprar</Nav.Link> <Nav.Link>Comprar</Nav.Link>
</LinkContainer> </LinkContainer>
......
...@@ -5,6 +5,10 @@ import MemberAdder from "./member/MemberAdder"; ...@@ -5,6 +5,10 @@ import MemberAdder from "./member/MemberAdder";
import MemberEditer from "./member/MemberEditer"; import MemberEditer from "./member/MemberEditer";
import MemberList from "./member/MemberList"; import MemberList from "./member/MemberList";
import ProductList from "./ProductList"; import ProductList from "./ProductList";
import CreateInventary from "./inventary/CreateInventary";
import InventaryList from "./inventary/InventaryList";
import ShowInventary from "./inventary/ShowInventary";
import CreateSupplier from "./inventary/CreateSupplier";
import Dashboard from "./Dashboard"; import Dashboard from "./Dashboard";
import OwnPassword from "./OwnPassword"; import OwnPassword from "./OwnPassword";
import Purchase from "./purchase/Purchase"; import Purchase from "./purchase/Purchase";
...@@ -49,6 +53,18 @@ function LogedPanel(props) { ...@@ -49,6 +53,18 @@ function LogedPanel(props) {
<Route path="/products"> <Route path="/products">
<ProductList /> <ProductList />
</Route> </Route>
<Route path="/inventary/add">
<CreateInventary />
</Route>
<Route path="/inventary/:id">
<ShowInventary />
</Route>
<Route path="/inventary">
<InventaryList />
</Route>
<Route path="/supplier/add">
<CreateSupplier />
</Route>
<Route path="/transaction/:id"> <Route path="/transaction/:id">
<ShowTransaction /> <ShowTransaction />
</Route> </Route>
......
...@@ -24,6 +24,8 @@ class ProductPicker extends React.Component { ...@@ -24,6 +24,8 @@ class ProductPicker extends React.Component {
let picks = this.props.picks; let picks = this.props.picks;
picks[index].amount = parseInt(amount); picks[index].amount = parseInt(amount);
this.props.setPicks(picks); this.props.setPicks(picks);
// trick it to redraw on each change
this.setState({ code: this.state.code });
} }
setPrice(index, price) { setPrice(index, price) {
...@@ -48,12 +50,17 @@ class ProductPicker extends React.Component { ...@@ -48,12 +50,17 @@ class ProductPicker extends React.Component {
return; return;
} }
let amount = 0;
if (this.props.amount) {
amount = 1;
}
picks.push({ picks.push({
code: product.code, code: product.code,
name: product.name, name: product.name,
origPrice: product.price,
price: product.price, price: product.price,
stock: product.stock, stock: product.stock,
amount: 1, amount,
}); });
this.props.setPicks(picks); this.props.setPicks(picks);
this.setState({ code: "" }); this.setState({ code: "" });
...@@ -86,12 +93,12 @@ class ProductPicker extends React.Component { ...@@ -86,12 +93,12 @@ class ProductPicker extends React.Component {
printMoney(p.price) + "" printMoney(p.price) + ""
)} )}
</Col> </Col>
{this.props.amount && ( {(this.props.amount || this.props.stock) && (
<Col> <Col>
<Form.Control <Form.Control
type="number" type="number"
min="1" min={this.props.amount ? "1" : Number.MIN_SAFE_INTEGER}
max={p.stock} max={this.props.amount ? p.stock : Number.MAX_SAFE_INTEGER}
placeholder="cantidad" placeholder="cantidad"
value={p.amount} value={p.amount}
onChange={(e) => this.setAmount(i, e.target.value)} onChange={(e) => this.setAmount(i, e.target.value)}
...@@ -119,7 +126,7 @@ class ProductPicker extends React.Component { ...@@ -119,7 +126,7 @@ class ProductPicker extends React.Component {
<Col> <Col>
<h6>Precio</h6> <h6>Precio</h6>
</Col> </Col>
{this.props.amount && ( {(this.props.amount || this.props.stock) && (
<Col> <Col>
<h6>Cantidad</h6> <h6>Cantidad</h6>
</Col> </Col>
...@@ -146,7 +153,7 @@ class ProductPicker extends React.Component { ...@@ -146,7 +153,7 @@ class ProductPicker extends React.Component {
/> />
</Col> </Col>
<Col xs={false} sm></Col> <Col xs={false} sm></Col>
{this.props.amount && <Col xs={false} sm></Col>} {(this.props.amount || this.props.stock) && <Col xs={false} sm></Col>}
<Col xs={false} sm={1}></Col> <Col xs={false} sm={1}></Col>
</Form.Group> </Form.Group>
</Fetcher> </Fetcher>
......
import React, { useState } from "react";
import { Redirect } from "react-router-dom";
import { Form, Row, Col, Button } from "react-bootstrap";
import ProductPicker from "../ProductPicker";
import Fetcher from "../Fetcher";
import Sender from "../Sender";
function supplierNameToId(suppliers, name) {
const found = suppliers.find((s) => s.name === name);
if (found) {
return found.ID;
}
return null;
}
function CreateInventary() {
const [suppliers, setSuppliers] = useState([]);
const [comment, setComment] = useState("");
const [supplier, setSupplier] = useState(null);
const [picks, setPicks] = useState([]);
const [redirect, setRedirect] = useState(null);
if (redirect !== null) {
return <Redirect to={"/inventary/" + redirect.ID} />;
}
const body = () => {
return {
comment,
supplier_id: supplierNameToId(suppliers, supplier),
products: picks.map((p) => {
return {
code: p.code,
price: p.price !== p.origPrice ? p.price : null,
stock: p.amount ? p.amount : null,
};
}),
};
};
const disabled = !picks;
const supplierOptions = [<option key=""></option>].concat(
suppliers.map((s) => <option key={s.ID}>{s.name}</option>)
);
// TODO: debug it, it doesn't send correctly
// it doesnt load picks when they change...
return (
<Sender url="/api/inventary" body={body} onSuccess={setRedirect}>
<Form.Group as={Row}>
<Form.Label as="legend" column sm={3}>
Proveedor
</Form.Label>
<Col sm={9}>
<Fetcher url="/api/supplier" onFetch={setSuppliers}>
<Form.Control
as="select"
onChange={(e) => setSupplier(e.target.value)}
>
{supplierOptions}
</Form.Control>
</Fetcher>
</Col>
</Form.Group>
<Form.Group as={Row}>
<Form.Label as="legend" column sm={3}>
Comentario
</Form.Label>
<Col sm={9}>
<Form.Control
placeholder="..."
value={comment}
onChange={(e) => setComment(e.target.value)}
/>
</Col>
</Form.Group>
<ProductPicker picks={picks} setPicks={setPicks} stock price />
<Form.Group as={Row}>
<Col>
<div className="text-right">
<Button type="submit" disabled={disabled}>
Añadir entrada
</Button>
</div>
</Col>
</Form.Group>
</Sender>
);
}
export default CreateInventary;
import React, { useState } from "react";
import { Redirect } from "react-router-dom";
import { Form, Row, Col, Button } from "react-bootstrap";
import Sender from "../Sender";
function CreateSupplier() {
const [name, setName] = useState("");
const [redirect, setRedirect] = useState(null);
if (redirect !== null) {
return <Redirect to="/inventary/" />;
}
const body = { name };
return (
<Sender url="/api/supplier" body={body} onSuccess={setRedirect}>
<Form.Group as={Row}>
<Form.Label as="legend" column sm={3}>
Nombre
</Form.Label>
<Col sm={9}>
<Form.Control
placeholder="nombre"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</Col>
</Form.Group>
<Form.Group as={Row}>
<Col>
<div className="text-right">
<Button type="submit" disabled={!name}>
Añadir proveedor
</Button>
</div>
</Col>
</Form.Group>
</Sender>
);
}
export default CreateSupplier;
import React, { useState } from "react";
import { Table, OverlayTrigger, Popover } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import Fetcher from "../Fetcher";
import { printDate, printMoney, printInventaryID } from "../util";
function supplier(entry) {
if (entry.supplier) {
return entry.supplier.name;
}
return "";
}
function inventaryOverlay(entry) {
const content = entry.products.map((p) => {
const stock = p.stock ? p.stock : "";
const price = p.price !== null ? printMoney(p.price) : "";
return (
<div key={"I" + entry.ID + "-" + p.ID}>
{p.product.name + ": " + stock + " " + price}
<br />
</div>
);
});
return (
<Popover>
<Popover.Title>{supplier(entry)}</Popover.Title>
<Popover.Content>{content}</Popover.Content>
</Popover>
);
}
function InventaryList() {
const [inventary, setInventary] = useState([]);
const entries = inventary.map((i) => (
<OverlayTrigger key={i.ID} overlay={inventaryOverlay(i)}>
<LinkContainer to={"/inventary/" + i.ID}>
<tr>
<td>{printInventaryID(i)}</td>
<td>{printDate(i.date)}</td>
<td>{i.member.name}</td>
<td>{supplier(i)}</td>
<td>{i.comment}</td>
</tr>
</LinkContainer>
</OverlayTrigger>
));
return (
<Fetcher url="/api/inventary" onFetch={setInventary}>
<Table className="text-center" responsive>
<thead>
<tr>
<th>ID</th>
<th>Fecha</th>
<th>Por</th>
<th>Proveedor</th>
<th>Comentario</th>
</tr>
</thead>
<tbody>{entries}</tbody>
</Table>
</Fetcher>
);
}
export default InventaryList;
import React, { useState } from "react";
import { useParams } from "react-router-dom";
import { Row, Col, Table } from "react-bootstrap";
import Fetcher from "../Fetcher";
import { printMoney, printDate, printInventaryID } from "../util";
function ShowInventary() {
const { id } = useParams();
const [entry, setEntry] = useState({ ID: 0, products: [] });
const products = entry.products.map((p) => (
<tr>
<td>{p.product.name}</td>
<td>{p.stock}</td>
<td>{p.price !== null ? printMoney(p.price) : ""}</td>
</tr>
));
return (
<Fetcher url={"/api/inventary/" + id} onFetch={setEntry}>
<Row>
<Col>{entry.supplier && <h3>{entry.supplier.name}</h3>}</Col>
<Col>
<p className="text-right">
{printDate(entry.date)} {printInventaryID(entry)}
<br />
{entry.member && entry.member.name}
</p>
</Col>
</Row>
<p>{entry.comment}</p>
<Table striped bordered hover responsive>
<thead>
<tr>
<th>producto</th>
<th>stock</th>
<th>precio</th>
</tr>
</thead>
<tbody>{products}</tbody>
</Table>
</Fetcher>
);
}
export default ShowInventary;
...@@ -23,7 +23,19 @@ function printRole(role) { ...@@ -23,7 +23,19 @@ function printRole(role) {
} }
function printTransactionID(transaction) { function printTransactionID(transaction) {
return "T-" + transaction.ID.toString().padStart(5, "0"); return printID("T", transaction);
}
function printInventaryID(inventary) {
return printID("I", inventary);
}
function printSupplierID(supplier) {
return printID("S", supplier);
}
function printID(pre, item) {
return pre + "-" + item.ID.toString().padStart(5, "0");
} }
function url(path) { function url(path) {
...@@ -57,4 +69,6 @@ export { ...@@ -57,4 +69,6 @@ export {
time2string, time2string,
daysAfterNow, daysAfterNow,
printTransactionID, printTransactionID,
printInventaryID,
printSupplierID,
}; };
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment