# блок схема
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%223%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%225%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%223%22%20parent%3D%221%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%BE%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2240%22%20width%3D%22120%22%20x%3D%22220%22%20y%3D%2230%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%224%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%225%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%227%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%225%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7%20%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2230%22%20width%3D%22120%22%20x%3D%22220%22%20y%3D%2290%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%226%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%227%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%229%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%227%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B%20%D0%B1%D0%B0%D0%B7%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2240%22%20width%3D%22180%22%20x%3D%22190%22%20y%3D%22140%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%228%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%229%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2211%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%229%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20er-%D0%B4%D0%B8%D0%B0%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2230%22%20width%3D%22180%22%20x%3D%22190%22%20y%3D%22200%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2210%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2211%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2213%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2211%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%B1%D0%B0%D0%B7%D1%8B%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85%20%D0%B2%20%D0%A1%D0%A3%D0%91%D0%94%20MySQL%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2240%22%20width%3D%22180%22%20x%3D%22190%22%20y%3D%22250%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2212%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2213%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2215%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2213%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0%20%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%BE%D0%B3%D0%BE%20%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B0%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2240%22%20width%3D%22180%22%20x%3D%22190%22%20y%3D%22310%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2214%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2215%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2219%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2215%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%97%D0%B0%D0%BF%D1%83%D1%81%D0%BA%20%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2230%22%20width%3D%22120%22%20x%3D%22220%22%20y%3D%22370%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2216%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%9F%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%BE%D0%B2%20%D0%B1%D0%B5%D0%B7%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%20%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D0%BE%D0%B2%2C%20%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8%20%D0%B8%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2270%22%20width%3D%22140%22%20x%3D%2280%22%20y%3D%22460%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2217%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2219%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0%3BexitY%3D0.5%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2216%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CArray%20as%3D%22points%22%3E%3CmxPoint%20x%3D%22150%22%20y%3D%22445%22%2F%3E%3C%2FArray%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2218%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2219%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D1%3BexitY%3D0.5%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2223%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2219%22%20parent%3D%221%22%20style%3D%22rhombus%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%9F%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%20%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%3F%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2250%22%20width%3D%22120%22%20x%3D%22220%22%20y%3D%22420%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2220%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2223%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0%3BexitY%3D0.5%3BexitDx%3D0%3BexitDy%3D0%3B%22%20target%3D%2225%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2221%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2223%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2227%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CArray%20as%3D%22points%22%3E%3CmxPoint%20x%3D%22545%22%20y%3D%22495%22%2F%3E%3C%2FArray%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2222%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2223%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3B%22%20target%3D%2229%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2223%22%20parent%3D%221%22%20style%3D%22rhombus%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%A0%D0%BE%D0%BB%D1%8C%20%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2250%22%20width%3D%22124%22%20x%3D%22350%22%20y%3D%22470%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2224%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2225%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D0.5%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2230%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2225%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%9F%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%BE%D0%B2%20%D0%B1%D0%B5%D0%B7%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%20%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D0%BE%D0%B2%2C%20%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8%20%D0%B8%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2270%22%20width%3D%22140%22%20x%3D%22210%22%20y%3D%22580%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2226%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2227%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D1%3BentryY%3D0.5%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2230%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2227%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%D0%9F%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%BE%D0%B2%20%D1%81%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5%D0%BC%20%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D0%BE%D0%B2%2C%20%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8%20%D0%B8%20%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0%3B%20%D0%9F%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%BE%D0%B2%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2270%22%20width%3D%22150%22%20x%3D%22470%22%20y%3D%22570%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2228%22%20edge%3D%221%22%20parent%3D%221%22%20source%3D%2229%22%20style%3D%22edgeStyle%3DorthogonalEdgeStyle%3Brounded%3D0%3BorthogonalLoop%3D1%3BjettySize%3Dauto%3Bhtml%3D1%3BexitX%3D0.5%3BexitY%3D1%3BexitDx%3D0%3BexitDy%3D0%3BentryX%3D1%3BentryY%3D0%3BentryDx%3D0%3BentryDy%3D0%3B%22%20target%3D%2230%22%3E%3CmxGeometry%20relative%3D%221%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2229%22%20parent%3D%221%22%20style%3D%22rounded%3D0%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%26lt%3Bdiv%26gt%3B%26amp%3Bnbsp%3B%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%B0%D0%BC%D0%B8%20%D0%B8%20%D0%B7%D0%B0%D0%BA%D0%B0%D0%B7%D0%B0%D0%BC%D0%B8%20(%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%2C%20%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%2C%20%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%2C%20%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5)%26lt%3B%2Fdiv%26gt%3B%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2270%22%20width%3D%22190%22%20x%3D%22317%22%20y%3D%22670%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3CmxCell%20id%3D%2230%22%20parent%3D%221%22%20style%3D%22ellipse%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3B%22%20value%3D%22%D0%BA%D0%BE%D0%BD%D0%B5%D1%86%22%20vertex%3D%221%22%3E%3CmxGeometry%20height%3D%2240%22%20width%3D%22120%22%20x%3D%22220%22%20y%3D%22780%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E




# readme
## ОПИСАНИЕ ПРОГРАММЫ
Это программа для компании, которая занимается продажей обуви. Реализованы модули для авторизации, окна администратора, менеджера, авторизированного клиента и неавторизированного клиента.

В программе доступны следующие роли:
- Администратор
- Менеджер
- Авторизованный клиент
- Неавторизованный клиент(гость)

У администратора есть следующие возможности: просмотр (с фильтрацией, сортировкой, поиском)/добавление/редактирование/удаление товаров, просмотр /добавление/редактирование/удаление заказов.

У менеджера есть следующие возможности: просмотр товаров (с фильтрацией, сортировкой, поиском), просмотр заказов.

У авторизованного клиент есть следующие возможности: просмотр товаров (без фильтрации, сортировки, поиска).

У неавторизованного клиента есть следующие возможности: просмотр товаров (без фильтрации, сортировки, поиска)

## ПРИМЕНЕНИЕ

### ПАРОЛИ
Администратор
- логин: admin
- пароль: admin123

Менеджер
- логин: manager
- пароль: manager123

Пользователь
- логин: client
- пароль: client123

### ЗАПУСК
Как запустить программу:
- скачайте файл с базой данных с расширением .sql
- выполните sql-скрипт для создания базы данных
- запустите main файл
- введите нужные логин и пароль




# окно админа
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>adminForm</class>
 <widget class="QWidget" name="adminForm">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>988</width>
    <height>715</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Окно админа</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_5">
   <item>
    <widget class="QTabWidget" name="tabWidget">
     <property name="currentIndex">
      <number>0</number>
     </property>
     <widget class="QWidget" name="tab">
      <attribute name="title">
       <string>Каталог</string>
      </attribute>
      <layout class="QVBoxLayout" name="verticalLayout_2">
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout_3">
         <item>
          <widget class="QPushButton" name="exitBtn_2">
           <property name="text">
            <string>Выйти</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QPushButton" name="addBtn_2">
           <property name="text">
            <string>Добавтиь</string>
           </property>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer_2">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
         <item>
          <widget class="QLabel" name="fio_label_2">
           <property name="text">
            <string/>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item>
        <widget class="QScrollArea" name="scrollArea">
         <property name="widgetResizable">
          <bool>true</bool>
         </property>
         <widget class="QWidget" name="scrollAreaWidgetContents">
          <property name="geometry">
           <rect>
            <x>0</x>
            <y>0</y>
            <width>936</width>
            <height>603</height>
           </rect>
          </property>
          <layout class="QVBoxLayout" name="verticalLayout">
           <item>
            <layout class="QHBoxLayout" name="horizontalLayout">
             <item>
              <widget class="QComboBox" name="amountCombo">
               <item>
                <property name="text">
                 <string>Все</string>
                </property>
               </item>
               <item>
                <property name="text">
                 <string>Меньше 15</string>
                </property>
               </item>
               <item>
                <property name="text">
                 <string>От 16 до 30</string>
                </property>
               </item>
               <item>
                <property name="text">
                 <string>от 31 до 100</string>
                </property>
               </item>
              </widget>
             </item>
             <item>
              <widget class="QComboBox" name="priceCombo">
               <item>
                <property name="text">
                 <string>Все</string>
                </property>
               </item>
               <item>
                <property name="text">
                 <string>По убыванию</string>
                </property>
               </item>
               <item>
                <property name="text">
                 <string>По возрастанию</string>
                </property>
               </item>
              </widget>
             </item>
             <item>
              <widget class="QLabel" name="label">
               <property name="text">
                <string>Поиск:</string>
               </property>
              </widget>
             </item>
             <item>
              <widget class="QLineEdit" name="searchLe"/>
             </item>
            </layout>
           </item>
           <item>
            <layout class="QVBoxLayout" name="itemLay"/>
           </item>
          </layout>
         </widget>
        </widget>
       </item>
      </layout>
     </widget>
     <widget class="QWidget" name="tab_2">
      <attribute name="title">
       <string>Заказы</string>
      </attribute>
      <layout class="QVBoxLayout" name="verticalLayout_4">
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout_2">
         <item>
          <widget class="QPushButton" name="exitBtn">
           <property name="text">
            <string>Выйти</string>
           </property>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
         <item>
          <widget class="QLabel" name="fio_label">
           <property name="text">
            <string/>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout_4">
         <item>
          <spacer name="horizontalSpacer_3">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
         <item>
          <widget class="QPushButton" name="addBtn">
           <property name="text">
            <string>Добавить</string>
           </property>
          </widget>
         </item>
        </layout>
       </item>
       <item>
        <widget class="QScrollArea" name="scrollArea_2">
         <property name="widgetResizable">
          <bool>true</bool>
         </property>
         <widget class="QWidget" name="scrollAreaWidgetContents_2">
          <property name="geometry">
           <rect>
            <x>0</x>
            <y>0</y>
            <width>936</width>
            <height>566</height>
           </rect>
          </property>
          <layout class="QVBoxLayout" name="verticalLayout_3">
           <item>
            <layout class="QVBoxLayout" name="orderLay"/>
           </item>
          </layout>
         </widget>
        </widget>
       </item>
      </layout>
     </widget>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>




# код бд
drop database demo;
create database demo;
use demo;

create table roles (
    id int auto_increment primary key,
    name varchar(20) not null
);

create table users (
    id int auto_increment primary key,
    login varchar(50) not null,
    passw varchar(50) not null,
    role_id int not null,
    last_name varchar(50),
    first_name varchar(50),
    middle_name varchar(50),
    foreign key (role_id) references roles(id)
);

create table categories (
    id int auto_increment primary key,
    name varchar(50) not null
);

create table suppliers (
    id int auto_increment primary key,
    company varchar(100) not null,
    phone varchar(20)
);

create table products (
    id int auto_increment primary key,
    name varchar(100) not null,
    price int not null,
    stock int not null,
    category_id int,
    supplier_id int,
    img_path varchar(255),
    discount int,
    foreign key (category_id) references categories(id),
    foreign key (supplier_id) references suppliers(id)
);

create table orders (
    id int auto_increment primary key,
    user_id int not null,
    order_date datetime,
    total_sum int,
    status varchar(50),
    address varchar(100),
    deliver_date date,
    foreign key (user_id) references users(id)
);

create table order_items (
    id int auto_increment primary key,
    order_id int not null,
    product_id int not null,
    quantity int not null,
    foreign key (order_id) references orders(id),
    foreign key (product_id) references products(id)
);

insert into roles (id, name) values
(1, 'admin'),
(2, 'client'),
(3, 'manager');

insert into users (id, login, passw, role_id, last_name, first_name, middle_name) values
(1, 'admin', 'admin123', 1, 'Иванов', 'Иван', 'Иванович'),
(2, 'client', 'client123', 2, 'Петров', 'Петр', 'Петрович'),
(3, 'manager', 'manager123', 3, 'Сидорова', 'Анна', 'Сергеевна');

insert into categories (id, name) values
(1, 'Электроника'),
(2, 'Одежда'),
(3, 'Книги');

insert into suppliers (id, company, phone) values
(1, 'ТехноПост', '+7 495 123-45-67'),
(2, 'Модный Стиль', '+7 812 987-65-43'),
(3, 'Книготорг', '+7 343 555-12-34');

insert into products (id, name, price, stock, category_id, supplier_id, img_path, discount) values
(1, 'Ноутбук', 75000, 10, 1, 1, 'notebook.jpg', 5000),
(2, 'Футболка', 1200, 50, 2, 2, 't-shirt.jpg',  0),
(3, 'Java Полное руководство', 1500, 20, 3, 3, 'java_book.jpg', 150);


insert into orders (id, user_id, order_date, total_sum, status, address, deliver_date) values
(1, 2, '2025-06-01 12:00:00', 76200, 'доставлен', 'г. Москва, ул. Примерная, д. 1', '2025-06-05'),
(2, 2, '2025-06-10 14:30:00', 1500, 'в обработке', 'г. Москва, ул. Воронцовская, д. 6', null),
(3, 3, '2025-06-12 09:00:00', 1200, 'отменен', 'г. Москва, ул. Пушкинская, д. 14', null);

insert into order_items (id, order_id, product_id, quantity) values
(1, 1, 1, 1),
(2, 1, 2, 1),
(3, 2, 3, 1),
(4, 3, 2, 1);






# код админа
import os
import sys
from tkinter import dialog

from PyQt6 import QtCore, QtGui, QtWidgets
from demo.db.database import Database
from demo.form.adminWind import Ui_adminForm


class Admin(QtWidgets.QWidget, Ui_adminForm):
    def __init__(self, fio):
        super().__init__()
        self.setupUi(self)
        self.db = Database()
        self.fio = fio
        self.fio_label.setText(self.fio)
        self.fio_label_2.setText(self.fio)
        self.main_ui()
        self.show_product()

    def main_ui(self):
    # присоединение всех кнопок
        self.amountCombo.currentIndexChanged.connect(self.show_product)
        self.priceCombo.currentIndexChanged.connect(self.show_product)
        self.searchLe.textChanged.connect(self.show_product)
        self.exitBtn.clicked.connect(self.exit_on)
        self.exitBtn_2.clicked.connect(self.exit_on)
        self.addBtn_2.clicked.connect(self.new_goods)
        self.show_orders()

    def show_product(self):
    # получение данных в сооветсвии с фильтром, поиском и сортировкой
        search_text = self.searchLe.text().strip()
        sort_by = self.priceCombo.currentText().strip()
        filt_by = self.amountCombo.currentText().strip()

        products = self.db.all_product()
        itog = products
        if search_text != "":
            itog = self.search_prod(itog, search_text)
        if sort_by != 'Все':
            itog = self.sort_prod(itog, sort_by)
        if filt_by != 'Все':
            itog = self.filt_prod(itog, filt_by)

        while self.itemLay.count():
            item = self.itemLay.takeAt(0)
            if item.widget():
                item.widget().deleteLater()

        for p in itog:
            group = self.create_cards(p)
            print(p)
            self.itemLay.addWidget(group)

    def create_cards(self, prod):
    # создание карточек всех позиций
        group = QtWidgets.QGroupBox()
        group.setMinimumHeight(120)
        lay = QtWidgets.QHBoxLayout(group)

        if prod['stock'] <= 0:
            group.setStyleSheet("QGroupBox { background-color: #d3d3d3; } QLabel { color: #666666; }")

        lb_photo = QtWidgets.QLabel()
        if prod['img_path'] and os.path.exists(self.resources_path(prod['img_path'])):
            photo = self.resources_path(prod['img_path'])
        else:
            photo = self.resources_path('resources/deafult.jpg')

        lb_photo.setPixmap(QtGui.QPixmap(photo).scaled(100, 100))
        lay.addWidget(lb_photo)

        status = "доступен" if prod['stock']>0 else "нет в наличии"
        final_price = prod['price'] - (prod['price'] * (prod['discount'] / 100))

        lbl = (f"Категория: {prod['c.name']} | Наимменование: {prod['name']}\n"
               f"Производитель: {prod['company']}\n"
               f"Цена: {prod['price']}\n"
               f"В наличии: {prod['stock']}\n"
               f"Статус: {status}")

        lbl_data = QtWidgets.QLabel(lbl)
        lbl_data.setWordWrap(True)
        lbl_data.setMinimumHeight(300)
        lay.addWidget(lbl_data)

        if prod['discount'] > 0:
            discount_lbl = QtWidgets.QLabel(f"Скидка: {prod['discount']}%\nИтого: {final_price} руб.")
            discount_lbl.setStyleSheet("color: green; font-weight: bold;")
            discount_lbl.setFixedWidth(120)
            lay.addWidget(discount_lbl)

        btn_lay = QtWidgets.QVBoxLayout()
        lay.addLayout(btn_lay)

        btn_update = QtWidgets.QPushButton("Обновить")
        btn_update.clicked.connect(lambda checked, p=prod: self.update_clicked(p))
        btn_lay.addWidget(btn_update)

        btn_delete = QtWidgets.QPushButton("Удалить")
        btn_delete.clicked.connect(lambda checked, p=prod: self.delete_clicked(p))
        btn_lay.addWidget(btn_delete)

        return group

    def search_prod(self, prod, search_text):
        # функция для поиска позиций
        if not search_text:
            data_prod = prod
        else:
            data_prod = [p for p in prod if search_text.lower() in str(p).lower()]

        return data_prod

    def sort_prod(self, prod, sort_by):
        # сортировка позиций по цене
        data_prod = []
        if sort_by == 'Все':
            data_prod = prod
        elif sort_by == 'По возрастанию':
            data_prod = sorted(prod, key=lambda x: int(x['price']))
        elif sort_by == "По убыванию":
            data_prod = sorted(prod, key=lambda x: int(x['price']), reverse=True)
        return data_prod

    def filt_prod(self, prod, filt_by):
        # фильтрация позиций по количеству на складе
        data_prod = []
        if filt_by == 'Все':
            data_prod = prod
        elif filt_by == 'Меньше 15':
            data_prod = [p for p in prod if p['stock'] < 15]
        elif filt_by == 'От 16 до 30':
            data_prod = [p for p in prod if 15 <= p['stock'] <= 30]
        elif filt_by == 'от 31 до 100':
            data_prod = [p for p in prod if 31 <= p['stock'] <= 100]
        return data_prod

    def exit_on(self):
    # для выхода из главного окна в окно авторизации
        from demo.auth import Auth
        self.wind = Auth()
        self.close()
        self.wind.show()

    def resources_path(self, path):
    # получение картинки
        try:
            base_path = os._MEIPASS
        except Exception:
            base_path = os.path.dirname(os.path.abspath(__file__))
        return os.path.join(base_path, path)

    def update_clicked(self, prod):
    # создание окна для редактирования позиций
        dialog = QtWidgets.QDialog(self)
        dialog.setWindowTitle('Редактирование')
        dialog.setModal(True)
        dialog.resize(350, 450)

        lay = QtWidgets.QVBoxLayout(dialog)

        lay.addWidget(QtWidgets.QLabel(f"Товар: {prod['name']}"))

        lay.addWidget(QtWidgets.QLabel("Новое название:"))
        name_edit = QtWidgets.QLineEdit(prod['name'])
        lay.addWidget(name_edit)
        price_edit = QtWidgets.QSpinBox()
        price_edit.setMaximum(999999)
        price_edit.setValue(prod['price'])
        lay.addWidget(QtWidgets.QLabel("Новая цена:"))
        lay.addWidget(price_edit)
        stock_edit = QtWidgets.QSpinBox()
        stock_edit.setMaximum(999999)
        stock_edit.setValue(prod['stock'])
        lay.addWidget(QtWidgets.QLabel("Новое количество:"))
        lay.addWidget(stock_edit)
        discount_edit = QtWidgets.QSpinBox()
        discount_edit.setMaximum(999999)
        discount_edit.setValue(prod['discount'] if prod['discount'] else 0)
        lay.addWidget(QtWidgets.QLabel("Новая скидка (руб):"))
        lay.addWidget(discount_edit)

        img_edit = QtWidgets.QLineEdit(prod['img_path'] if prod['img_path'] else "")
        img_btn = QtWidgets.QPushButton('Выбрать новое фото')
        lay.addWidget(QtWidgets.QLabel("Путь к фото:"))
        lay.addWidget(img_edit)
        lay.addWidget(img_btn)

        btn_ok = QtWidgets.QPushButton("Сохранить")
        lay.addWidget(btn_ok)

        def select_photo():
        # функция для выбора своего фото
            file_path, _ = QtWidgets.QFileDialog.getOpenFileName(dialog, "Выбрать фото", "", "Images (*.png *.jpg *.jpeg *.bmp)")
            if file_path:
                import shutil
                import os
                try:
                    base_path = sys._MEIPASS
                    photo_dir = os.path.join(os.path.dirname(base_path), "photo")
                except AttributeError:
                    current_dir = os.getcwd()
                    photo_dir = os.path.join(current_dir, "photo")

                os.makedirs(photo_dir, exist_ok=True)
                file_name = os.path.basename(file_path)
                new_path = os.path.join(photo_dir, file_name)
                shutil.copy2(file_path, new_path)
                img_edit.setText(f"photo/{file_name}")
                QtWidgets.QMessageBox.information(dialog, "Успех", "Фото обновлено")

        img_btn.clicked.connect(select_photo)

        def on_update():
        # обновление в соотсветсвии с новыми данными
            # обновление товара
            self.db.update_product(prod['id'], name_edit.text(), price_edit.value(), stock_edit.value(),
                           prod['category_id'], prod['supplier_id'], img_edit.text(), discount_edit.value())
            QtWidgets.QMessageBox.information(dialog, "Готово", f"Товар {prod['name']} обновлен")
            dialog.accept()
            self.show_product()

        btn_ok.clicked.connect(on_update)
        dialog.exec()

    def delete_clicked(self, prod):
        # удаление позиции в соответсвии с id

        reply = QtWidgets.QMessageBox.question(self, "Удаление", f"Удалить {prod['name']}?",
                                               QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)
        if reply == QtWidgets.QMessageBox.StandardButton.Yes:
            self.db.delete_product(prod['id'])
            QtWidgets.QMessageBox.information(self, "Готово", f"Товар {prod['name']} удален")
            self.show_product()

    def new_goods(self):
        # создание нового окна для добавления позиции
        dialog = QtWidgets.QDialog(self)
        dialog.setWindowTitle("Добавление товара")
        dialog.setModal(True)
        dialog.resize(350, 450)

        layout = QtWidgets.QVBoxLayout(dialog)

        layout.addWidget(QtWidgets.QLabel("Название товара:"))
        name_edit = QtWidgets.QLineEdit()
        layout.addWidget(name_edit)

        layout.addWidget(QtWidgets.QLabel("Цена:"))
        price_edit = QtWidgets.QSpinBox()
        price_edit.setMaximum(999999)
        layout.addWidget(price_edit)

        layout.addWidget(QtWidgets.QLabel("Количество на складе:"))
        stock_edit = QtWidgets.QSpinBox()
        stock_edit.setMaximum(999999)
        layout.addWidget(stock_edit)

        layout.addWidget(QtWidgets.QLabel("Категория:"))
        category_combo = QtWidgets.QComboBox()
        categories = self.db.select_categories()
        for cat in categories:
            category_combo.addItem(cat['name'], cat['id'])
        layout.addWidget(category_combo)

        layout.addWidget(QtWidgets.QLabel("Поставщик:"))
        supplier_combo = QtWidgets.QComboBox()
        suppliers = self.db.select_suppliers()
        for sup in suppliers:
            supplier_combo.addItem(sup['company'], sup['id'])
        layout.addWidget(supplier_combo)

        layout.addWidget(QtWidgets.QLabel("Скидка (руб):"))
        discount_edit = QtWidgets.QSpinBox()
        discount_edit.setMaximum(999999)
        layout.addWidget(discount_edit)

        layout.addWidget(QtWidgets.QLabel("Фото товара:"))
        img_layout = QtWidgets.QHBoxLayout()
        img_edit = QtWidgets.QLineEdit()
        img_edit.setReadOnly(True)
        img_btn = QtWidgets.QPushButton("Выбрать фото")

        def select_photo():
            # выбор фото для позиции
            file_path, _ = QtWidgets.QFileDialog.getOpenFileName(dialog, "Выбрать фото", "", "Images (*.png *.jpg *.jpeg *.bmp)")
            if file_path:
                import shutil
                import os

                if getattr(sys, 'frozen', False):
                    current_dir = os.path.dirname(sys.executable)
                else:
                    current_dir = os.getcwd()

                photo_dir = os.path.join(current_dir, "photo")
                os.makedirs(photo_dir, exist_ok=True)
                file_name = os.path.basename(file_path)
                new_path = os.path.join(photo_dir, file_name)
                shutil.copy2(file_path, new_path)
                img_edit.setText(f"photo/{file_name}")
                QtWidgets.QMessageBox.information(dialog, "Успех", f"Фото сохранено в папку photo")

        img_btn.clicked.connect(select_photo)
        img_layout.addWidget(img_edit)
        img_layout.addWidget(img_btn)
        layout.addLayout(img_layout)

        btn_ok = QtWidgets.QPushButton("Добавить")
        layout.addWidget(btn_ok)

        def on_add():
            # добавление товара в соответсвии с введенными данными
            if name_edit.text():
                self.db.add_product(
                    name_edit.text(),
                    price_edit.value(),
                    stock_edit.value(),
                    category_combo.currentData(),
                    supplier_combo.currentData(),
                    img_edit.text(),
                    discount_edit.value()
                )
                QtWidgets.QMessageBox.information(dialog, "Готово", f"Товар {name_edit.text()} добавлен")
                dialog.accept()
                self.show_product()
            else:
                QtWidgets.QMessageBox.warning(dialog, "Ошибка", "Введите название товара")

        btn_ok.clicked.connect(on_add)
        dialog.exec()


    def show_orders(self):
        # вывод всех заказов
        orders = self.db.select_orders()

        while self.orderLay.count():
            item = self.orderLay.takeAt(0)
            if item.widget():
                item.widget().deleteLater()

        for order in orders:
            group = self.create_order_group(order)
            self.orderLay.addWidget(group)

    def create_order_group(self, order):
        # создание карточек заказов
        group = QtWidgets.QGroupBox()
        group_layout = QtWidgets.QHBoxLayout(group)

        left_layout = QtWidgets.QVBoxLayout()
        left_layout.addWidget(QtWidgets.QLabel(f"Артикул заказа: {order['id']}"))
        left_layout.addWidget(QtWidgets.QLabel(f"Статус заказа: {order['status']}"))
        left_layout.addWidget(QtWidgets.QLabel(f"Адрес пункта выдачи: {order['address']}"))
        left_layout.addWidget(QtWidgets.QLabel(f"Дата заказа: {order['deliver_date']}"))

        left_widget = QtWidgets.QWidget()
        left_widget.setLayout(left_layout)
        group_layout.addWidget(left_widget)

        middle_layout = QtWidgets.QVBoxLayout()
        middle_layout.addWidget(QtWidgets.QLabel(f"Адрес доставки: {order['address'] if order['address'] else 'не назначена'}"))

        middle_widget = QtWidgets.QWidget()
        middle_widget.setLayout(middle_layout)
        group_layout.addWidget(middle_widget)

        btn_layout = QtWidgets.QVBoxLayout()
        btn_edit = QtWidgets.QPushButton("Редактировать")
        btn_edit.clicked.connect(lambda checked, o=order: self.edit_order_clicked(o))
        btn_delete = QtWidgets.QPushButton("Удалить")
        btn_delete.clicked.connect(lambda checked, o=order: self.delete_order_clicked(o))
        btn_layout.addWidget(btn_edit)
        btn_layout.addWidget(btn_delete)

        btn_widget = QtWidgets.QWidget()
        btn_widget.setLayout(btn_layout)
        group_layout.addWidget(btn_widget)

        return group

    def edit_order_clicked(self, order):
        # создание нового окна для обновления заказа
        dialog = QtWidgets.QDialog(self)
        dialog.setWindowTitle(f"Редактирование заказа №{order['id']}")
        dialog.setModal(True)
        dialog.resize(300, 250)

        layout = QtWidgets.QVBoxLayout(dialog)

        layout.addWidget(QtWidgets.QLabel("Статус заказа:"))
        status_combo = QtWidgets.QComboBox()
        status_combo.addItems(["в обработке", "доставлен", "отменен"])
        status_combo.setCurrentText(order['status'])
        layout.addWidget(status_combo)

        layout.addWidget(QtWidgets.QLabel("Дата доставки:"))
        date_edit = QtWidgets.QDateEdit()
        if order['deliver_date']:
            if isinstance(order['deliver_date'], str):
                date_edit.setDate(QtWidgets.QDate.fromString(order['deliver_date'], "yyyy-MM-dd"))
            else:
                date_edit.setDate(QtCore.QDate(order['deliver_date'].year, order['deliver_date'].month, order['deliver_date'].day))
        else:
            date_edit.setDate(QtCore.QDate.currentDate().addDays(3))
        date_edit.setCalendarPopup(True)
        date_edit.setDisplayFormat("yyyy-MM-dd")
        layout.addWidget(date_edit)

        btn_save = QtWidgets.QPushButton("Сохранить")
        layout.addWidget(btn_save)

        def on_save():
            self.db.update_order(order['id'], status_combo.currentText(), date_edit.date().toString("yyyy-MM-dd"))
            QtWidgets.QMessageBox.information(dialog, "Готово", f"Заказ №{order['id']} обновлен")
            dialog.accept()
            self.show_orders()

        btn_save.clicked.connect(on_save)
        dialog.exec()

    def delete_order_clicked(self, order):
        # удаление заказа по id
        reply = QtWidgets.QMessageBox.question(self, "Удаление", f"Удалить заказ №{order['id']}?",
                                     QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)
        if reply == QtWidgets.QMessageBox.StandardButton.Yes:
            self.db.delete_order(order['id'])
            QtWidgets.QMessageBox.information(self, "Готово", f"Заказ №{order['id']} удален")
            self.show_orders()

    def add_order_clicked(self):
        # создание нового окна для добавления заказа
        dialog = QtWidgets.QDialog(self)
        dialog.setWindowTitle("Создание заказа")
        dialog.setModal(True)
        dialog.resize(350, 400)

        layout = QtWidgets.QVBoxLayout(dialog)

        layout.addWidget(QtWidgets.QLabel("Клиент:"))
        user_combo = QtWidgets.QComboBox()
        users = self.db.get_users()
        for user in users:
            user_combo.addItem(user['full_name'], user['id'])
        layout.addWidget(user_combo)

        layout.addWidget(QtWidgets.QLabel("Адрес доставки:"))
        address_edit = QtWidgets.QLineEdit()
        layout.addWidget(address_edit)

        layout.addWidget(QtWidgets.QLabel("Дата доставки:"))
        date_edit = QtWidgets.QDateEdit()
        date_edit.setDate(QtWidgets.QDate.currentDate().addDays(3))
        date_edit.setCalendarPopup(True)
        date_edit.setDisplayFormat("yyyy-MM-dd")
        layout.addWidget(date_edit)

        layout.addWidget(QtWidgets.QLabel("Товар:"))
        product_combo = QtWidgets.QComboBox()
        products = self.db.get_products_for_order()
        for p in products:
            product_combo.addItem(f"{p['name']} - {p['price']} руб. (в наличии: {p['stock']})", p['id'])
        layout.addWidget(product_combo)

        layout.addWidget(QtWidgets.QLabel("Количество:"))
        quantity_spin = QtWidgets.QSpinBox()
        quantity_spin.setMinimum(1)

        def update_max_quantity():
            # обновление количества на складе
            product_id = product_combo.currentData()
            product = next(p for p in products if p['id'] == product_id)
            quantity_spin.setMaximum(product['stock'])

        product_combo.currentIndexChanged.connect(update_max_quantity)
        update_max_quantity()

        layout.addWidget(quantity_spin)

        btn_ok = QtWidgets.QPushButton("Создать заказ")
        layout.addWidget(btn_ok)

        def on_create():
            # создание нового заказа
            if not address_edit.text():
                QtWidgets.QMessageBox.warning(dialog, "Ошибка", "Введите адрес доставки")
                return

            product_id = product_combo.currentData()
            product = next(p for p in products if p['id'] == product_id)
            quantity = quantity_spin.value()

            if quantity > product['stock']:
                QtWidgets.QMessageBox.warning(dialog, "Ошибка", f"Недостаточно товара. В наличии: {product[3]}")
                return

            total = product['price'] * quantity

            order_id = self.db.create_order(user_combo.currentData(), total, address_edit.text(),
                                    date_edit.date().toString("yyyy-MM-dd"))
            self.db.add_order_item(order_id, product_id, quantity)
            self.db.update_product_stock(product_id, quantity)

            QtWidgets.QMessageBox.information(dialog, "Готово", f"Заказ №{order_id} создан")
            dialog.accept()
            self.show_orders()
            self.show_product()

        btn_ok.clicked.connect(on_create)
        dialog.exec()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    wind = Admin('Иванов Иван Иванович')
    wind.show()
    sys.exit(app.exec())







# код бд для всего
import pymysql

class Database:
    def __init__(self):
        self.conn = pymysql.connect(
            host='localhost',
            user='root',
            password='root',
            database='demo',
            cursorclass=pymysql.cursors.DictCursor
        )
        self.cursor = self.conn.cursor()

    def check_user(self, login, password):
    # проверка на существование пользователя
        query = """
        select * from users where login=%s and passw=%s;
        """
        self.cursor.execute(query, (login, password))
        return self.cursor.fetchone()

    def all_product(self):
    # фукнция для получения всех продуктов
        query = """
        select p.*, c.name, s.company
        from products p
        join categories c on c.id = p.category_id
        join suppliers s on s.id = p.supplier_id;
                """
        self.cursor.execute(query)
        return self.cursor.fetchall()

    def update_product(self, id, name, price, stock, category_id, supplier_id, img_path, discount):
    # обновление позиции в соответсвии с введеными данными
        try:
            query = """
                UPDATE products
                SET name=%s, price=%s, stock=%s, category_id=%s, supplier_id=%s, img_path=%s, discount=%s
                WHERE id=%s
            """
            self.cursor.execute(query, (name, price, stock, category_id, supplier_id, img_path, discount, id))
            self.conn.commit()
            return True
        except Exception as e:
            print(e)
            self.conn.rollback()
            return False

    def add_product(self, name, price, stock, category_id, supplier_id, img_path, discount):
        # добавить новый продукт
        try:
            query = """
            INSERT INTO products (name, price, stock, category_id, supplier_id, img_path, discount)
            VALUES (%s, %s, %s, %s, %s, %s, %s)
            """
            self.cursor.execute(query, (name, price, stock, category_id, supplier_id, img_path, discount))
            self.conn.commit()
            return True
        except Exception as e:
            print(e)
            self.conn.rollback()
            return False

    def delete_product(self, id):
        # удалить продукт
        try:
            self.cursor.execute("DELETE FROM products WHERE id=%s", (id,))
            self.conn.commit()
            return True
        except Exception as e:
            print(e)
            self.conn.rollback()
            return False

    def select_categories(self):
        # получение категории товаров
        self.cursor.execute("SELECT id, name FROM categories")
        return self.cursor.fetchall()

    def select_suppliers(self):
        # получение поставщиков
        self.cursor.execute("SELECT id, company FROM suppliers")
        return self.cursor.fetchall()

    def select_orders(self):
        # получение информации о всех заказах
        self.cursor.execute("""
            SELECT o.id, o.order_date, o.total_sum, o.status, o.address, o.deliver_date,
                   CONCAT(u.last_name, ' ', u.first_name, ' ', COALESCE(u.middle_name, '')) as user_name
            FROM orders o
            JOIN users u ON o.user_id = u.id
            ORDER BY o.order_date DESC
        """)
        return self.cursor.fetchall()

    def update_order(self, order_id, status, deliver_date):
        # обновление информации о заказе в соответсвии с новыми даннами
        self.cursor.execute("UPDATE orders SET status = %s, deliver_date = %s WHERE id = %s",
                       (status, deliver_date, order_id))

    def delete_order(self, order_id):
        # удалить заказ в соовтветсвии с id
        self.cursor.execute("DELETE FROM order_items WHERE order_id = %s", (order_id,))
        self.cursor.execute("DELETE FROM orders WHERE id = %s", (order_id,))

    def create_order(self, user_id, total_sum, address, deliver_date):
        # создание нового заказа
        self.cursor.execute("""
            INSERT INTO orders (user_id, order_date, total_sum, status, address, deliver_date)
            VALUES (%s, NOW(), %s, 'в обработке', %s, %s)
        """, (user_id, total_sum, address, deliver_date))
        return self.cursor.lastrowid

    def add_order_item(self, order_id, product_id, quantity):
        # добавление элемента заказа
        self.cursor.execute("""
            INSERT INTO order_items (order_id, product_id, quantity)
            VALUES (%s, %s, %s)
        """, (order_id, product_id, quantity))

    def get_users(self):
        # получить пользователя для выбора его при создании нового заказа
        self.cursor.execute("""
            SELECT id, CONCAT(last_name, ' ', first_name, ' ', COALESCE(middle_name, '')) as full_name
            FROM users WHERE role_id = 2
        """)
        return self.cursor.fetchall()

    def get_products_for_order(self):
        # получение продуктов с количеством больше 0
        self.cursor.execute("SELECT id, name, price, stock FROM products WHERE stock > 0")
        return self.cursor.fetchall()

    def update_product_stock(self, product_id, quantity):
        # обновление количества товара
        self.cursor.execute("UPDATE products SET stock = stock - %s WHERE id = %s", (quantity, product_id))




# main код
from PyQt6 import QtWidgets, QtCore, QtGui
from auth import *
from qt_material import apply_stylesheet
from auth import Auth

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    apply_stylesheet(app, theme='dark_red.xml')
    wind = Auth()
    wind.show()
    sys.exit(app.exec())

"""
🌙 Тёмные темы (Dark)
Название темы
Описание
dark_amber.xml
Тёмная с янтарным акцентом
dark_blue.xml
Тёмная с синим акцентом
dark_cyan.xml
Тёмная с циановым акцентом
dark_lightgreen.xml
Тёмная с салатовым акцентом
dark_pink.xml
Тёмная с розовым акцентом
dark_purple.xml
Тёмная с фиолетовым акцентом
dark_red.xml
Тёмная с красным акцентом
dark_teal.xml
Тёмная с бирюзовым акцентом
dark_yellow.xml
Тёмная с жёлтым акцентом
 
☀️ Светлые темы (Light)
apply_stylesheet(app, theme='light_blue.xml', invert_secondary=True)
Название темы
Описание
light_amber.xml
Светлая с янтарным акцентом
light_blue.xml
Светлая с синим акцентом
light_cyan.xml
Светлая с циановым акцентом
light_cyan_500.xml
Светлая с циановым (оттенок 500)
light_lightgreen.xml
Светлая с салатовым акцентом
light_pink.xml
Светлая с розовым акцентом
light_purple.xml
Светлая с фиолетовым акцентом
light_red.xml
Светлая с красным акцентом
light_teal.xml
Светлая с бирюзовым акцентом
light_yellow.xml
Светлая с жёлтым акцентом
"""




# как делать pyinstaller
pyinstaller --onefile --windowed --icon="resources/icons/Лопушок.ico" --add-data "resources;resources" --hidden-import pymysql trying.py





# ui авторизация
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>authWind</class>
 <widget class="QWidget" name="authWind">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="acceptDrops">
   <bool>false</bool>
  </property>
  <property name="windowTitle">
   <string>Окно авторизации</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
     <item>
      <widget class="QLabel" name="label">
       <property name="font">
        <font>
         <pointsize>14</pointsize>
        </font>
       </property>
       <property name="text">
        <string>Авторизация</string>
       </property>
      </widget>
     </item>
     <item>
      <spacer name="horizontalSpacer_2">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>40</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QFormLayout" name="formLayout">
     <item row="0" column="0">
      <widget class="QLabel" name="loginLabel">
       <property name="text">
        <string>login</string>
       </property>
      </widget>
     </item>
     <item row="0" column="1">
      <widget class="QLineEdit" name="loginLineEdit"/>
     </item>
     <item row="1" column="0">
      <widget class="QLabel" name="passwordLabel">
       <property name="text">
        <string>password</string>
       </property>
      </widget>
     </item>
     <item row="1" column="1">
      <widget class="QLineEdit" name="passwordLineEdit">
       <property name="contextMenuPolicy">
        <enum>Qt::PreventContextMenu</enum>
       </property>
       <property name="echoMode">
        <enum>QLineEdit::Password</enum>
       </property>
      </widget>
     </item>
    </layout>
   </item>
   <item>
    <layout class="QVBoxLayout" name="verticalLayout">
     <item>
      <widget class="QPushButton" name="authBtn">
       <property name="text">
        <string>Войти</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="guestBtn">
       <property name="text">
        <string>Войти как гость</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>




# код авторизации
import os
import sys

from PyQt6 import QtCore, QtGui, QtWidgets
from db.database import Database
from form.authWind import Ui_authWind
from guest import Guest
from admin import Admin
from client import Client
from manager import Manager


class Auth(QtWidgets.QWidget, Ui_authWind):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.db = Database()
        self.authBtn.clicked.connect(self.auth)
        self.guestBtn.clicked.connect(self.open_guest)
        self.setWindowIcon(QtGui.QIcon(self.resources_path("resources/Лопушок.ico")))

    def resources_path(self, path):
        try:
            base_path = os._MEIPASS
        except Exception:
            base_path = os.path.dirname(os.path.abspath(__file__))
        return os.path.join(base_path, path)

    def auth(self):
        login = self.loginLineEdit.text().strip()
        password = self.passwordLineEdit.text().strip()

        if not password or not login:
            QtWidgets.QMessageBox.warning(self, 'Ошибка', 'Заполните все поля')
            return
        user = self.db.check_user(login, password)

        if not user:
            QtWidgets.QMessageBox.warning(self, 'Ошибка', 'Такого пользователя не существует')
            return

        role = user['role_id']
        fio = f"{user['last_name']} {user['first_name']} {user['middle_name']}"

        if role == 1:
            self.wind = Admin(fio)
            QtWidgets.QMessageBox.information(self, 'Успех', 'Вы вошли как админ')
            self.close()
            self.wind.show()
        elif role == 2:
            self.wind = Client(fio)
            QtWidgets.QMessageBox.information(self, 'Успех', 'Вы вошли как клиент')
            self.close()
            self.wind.show()
        elif role == 3:
            self.wind = Manager(fio)
            QtWidgets.QMessageBox.information(self, 'Успех', 'Вы вошли как менеджер')
            self.close()
            self.wind.show()

    def open_guest(self):
        self.wind = Guest()
        self.close()
        self.wind.show()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    wind = Auth()
    wind.show()
    sys.exit(app.exec())