+ `);
+ }
+
+});
+
+frappe.ready(function() {
+ if (window.location.pathname !== "/wishlist") {
+ $(".wishlist").toggleClass('hidden', true);
+ wishlist.set_wishlist_count();
+ } else {
+ wishlist.bind_move_to_cart_action();
+ wishlist.bind_remove_action();
+ }
+
+});
\ No newline at end of file
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 490a7c4af73..fbb26a8008c 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -1,16 +1,17 @@
@import "frappe/public/scss/common/mixins";
-body.product-page {
- background: var(--gray-50);
+:root {
+ --green-info: #38A160;
+ --product-bg-color: white;
+ --body-bg-color: var(--gray-50);
}
+body.product-page {
+ background: var(--body-bg-color);
+}
.item-breadcrumbs {
.breadcrumb-container {
- ol.breadcrumb {
- background-color: var(--gray-50) !important;
- }
-
a {
color: var(--gray-900);
}
@@ -61,9 +62,21 @@ body.product-page {
}
}
+.no-image-item {
+ height: 340px;
+ width: 340px;
+ background: var(--gray-100);
+ border-radius: var(--border-radius);
+ font-size: 2rem;
+ color: var(--gray-500);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
.item-card-group-section {
.card {
- height: 360px;
+ height: 100%;
align-items: center;
justify-content: center;
@@ -73,6 +86,19 @@ body.product-page {
}
}
+ .card:hover, .card:focus-within {
+ .btn-add-to-cart-list {
+ visibility: visible;
+ }
+ .like-action {
+ visibility: visible;
+ }
+ .btn-explore-variants {
+ visibility: visible;
+ }
+ }
+
+
.card-img-container {
height: 210px;
width: 100%;
@@ -86,14 +112,28 @@ body.product-page {
.no-image {
@include flex(flex, center, center, null);
- height: 200px;
- margin: 0 auto;
- margin-top: var(--margin-xl);
+ height: 220px;
+ background: var(--gray-100);
+ width: 100%;
+ border-radius: var(--border-radius) var(--border-radius) 0 0;
+ font-size: 2rem;
+ color: var(--gray-500);
+ }
+
+ .no-image-list {
+ @include flex(flex, center, center, null);
+ height: 150px;
background: var(--gray-100);
- width: 80%;
border-radius: var(--border-radius);
font-size: 2rem;
color: var(--gray-500);
+ margin-top: 15px;
+ margin-bottom: 15px;
+ }
+
+ .card-body-flex {
+ display: flex;
+ flex-direction: column;
}
.product-title {
@@ -126,10 +166,70 @@ body.product-page {
font-weight: 600;
color: var(--text-color);
margin: var(--margin-sm) 0;
+ margin-bottom: auto !important;
+
+ .striked-price {
+ font-weight: 500;
+ font-size: 15px;
+ color: var(--gray-500);
+ }
+ }
+
+ .product-info-green {
+ color: var(--green-info);
+ font-weight: 600;
}
.item-card {
padding: var(--padding-sm);
+ min-width: 300px;
+ }
+
+ .wishlist-card {
+ padding: var(--padding-sm);
+ min-width: 260px;
+ .card-body-flex {
+ display: flex;
+ flex-direction: column;
+ }
+ }
+}
+
+#products-list-area, #products-grid-area {
+ padding: 0 5px;
+}
+
+.list-row {
+ background-color: white;
+ padding-bottom: 1rem;
+ padding-top: 1.5rem !important;
+ border-radius: 8px;
+ border-bottom: 1px solid var(--gray-50);
+
+ &:hover, &:focus-within {
+ box-shadow: 0px 16px 60px rgba(0, 0, 0, 0.08), 0px 8px 30px -20px rgba(0, 0, 0, 0.04);
+ transition: box-shadow 400ms;
+
+ .btn-add-to-cart-list {
+ visibility: visible;
+ }
+ .like-action-list {
+ visibility: visible;
+ }
+ .btn-explore-variants {
+ visibility: visible;
+ }
+ }
+
+ .product-code {
+ padding-top: 0 !important;
+ }
+
+ .btn-explore-variants {
+ min-width: 135px;
+ max-height: 30px;
+ float: right;
+ padding: 0.25rem 1rem;
}
}
@@ -174,28 +274,76 @@ body.product-page {
}
}
+.product-filter {
+ width: 14px !important;
+ height: 14px !important;
+}
+
+.discount-filter {
+ &:before {
+ width: 14px !important;
+ height: 14px !important;
+ }
+}
+
+.list-image {
+ border: none !important;
+ overflow: hidden;
+ max-height: 200px;
+ background-color: white;
+}
+
.product-container {
@include card($padding: var(--padding-md));
- min-height: 70vh;
+ background-color: var(--product-bg-color) !important;
+ min-height: fit-content;
.product-details {
- max-width: 40%;
- margin-left: -30px;
+ max-width: 50%;
.btn-add-to-cart {
- font-size: var(--text-base);
+ font-size: 14px;
+ }
+ }
+
+ &.item-main {
+ .product-image {
+ width: 100%;
+ }
+ }
+
+ .expand {
+ max-width: 100% !important; // expand in absence of slideshow
+ }
+
+ @media (max-width: 789px) {
+ .product-details {
+ max-width: 90% !important;
+
+ .btn-add-to-cart {
+ font-size: 14px;
+ }
+ }
+ }
+
+ .btn-add-to-wishlist {
+ svg use {
+ stroke: #F47A7A;
+ }
+ }
+
+ .btn-view-in-wishlist {
+ svg use {
+ fill: #F47A7A;
+ stroke: none;
}
}
.product-title {
- font-size: 24px;
+ font-size: 16px;
font-weight: 600;
color: var(--text-color);
- }
-
- .product-code {
- color: var(--text-muted);
- font-size: 13px;
+ padding: 0 !important;
}
.product-description {
@@ -232,7 +380,7 @@ body.product-page {
max-height: 430px;
}
- overflow: scroll;
+ overflow: auto;
}
.item-slideshow-image {
@@ -251,29 +399,114 @@ body.product-page {
.item-cart {
.product-price {
- font-size: 20px;
+ font-size: 22px;
color: var(--text-color);
font-weight: 600;
.formatted-price {
color: var(--text-muted);
- font-size: var(--text-base);
+ font-size: 14px;
}
}
.no-stock {
font-size: var(--text-base);
}
+
+ .offers-heading {
+ font-size: 16px !important;
+ color: var(--text-color);
+ .tag-icon {
+ --icon-stroke: var(--gray-500);
+ }
+ }
+
+ .w-30-40 {
+ width: 30%;
+
+ @media (max-width: 992px) {
+ width: 40%;
+ }
+ }
+ }
+
+ .tab-content {
+ font-size: 14px;
+ }
+}
+
+// Item Recommendations
+.recommended-item-section {
+ padding-right: 0;
+
+ .recommendation-header {
+ font-size: 16px;
+ font-weight: 500
+ }
+
+ .recommendation-container {
+ padding: .5rem;
+ min-height: 0px;
+
+ .r-item-image {
+ width: 40%;
+
+ .r-product-image {
+ padding: 2px 15px;
+ }
+
+ .no-image-r-item {
+ display: flex; justify-content: center;
+ background-color: var(--gray-200);
+ align-items: center;
+ color: var(--gray-400);
+ margin-top: .15rem;
+ border-radius: 6px;
+ height: 100%;
+ font-size: 24px;
+ }
+ }
+
+ .r-item-info {
+ font-size: 14px;
+ padding-right: 0;
+ width: 60%;
+
+ a {
+ color: var(--gray-800);
+ font-weight: 400;
+ }
+
+ .item-price {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--text-color);
+ }
+
+ .striked-item-price {
+ font-weight: 500;
+ color: var(--gray-500);
+ }
+ }
+ }
+}
+
+.product-code {
+ padding: .5rem 0;
+ color: var(--text-muted);
+ font-size: 14px;
+ .product-item-group {
+ padding-right: .25rem;
+ border-right: solid 1px var(--text-muted);
+ }
+
+ .product-item-code {
+ padding-left: .5rem;
}
}
.item-configurator-dialog {
- .modal-header {
- padding: var(--padding-md) var(--padding-xl);
- }
-
.modal-body {
- padding: 0 var(--padding-xl);
padding-bottom: var(--padding-xl);
.status-area {
@@ -313,20 +546,74 @@ body.product-page {
}
}
-.cart-icon {
- .cart-badge {
- position: relative;
- top: -10px;
- left: -12px;
- background: var(--red-600);
- width: 16px;
- align-items: center;
- height: 16px;
- font-size: 10px;
- border-radius: 50%;
+.sub-category-container {
+ padding-bottom: .5rem;
+ margin-bottom: 1.25rem;
+ border-bottom: 1px solid var(--table-border-color);
+
+ .heading {
+ color: var(--gray-500);
}
}
+.scroll-categories {
+ white-space: nowrap;
+ overflow-x: auto;
+
+ .category-pill {
+ margin: 0px 4px;
+ display: inline-block;
+ padding: 6px 12px;
+ background-color: #ecf5fe;
+ width: fit-content;
+ font-size: 14px;
+ border-radius: 18px;
+ color: var(--blue-500);
+ }
+}
+
+
+.shopping-badge {
+ position: relative;
+ top: -10px;
+ left: -12px;
+ background: var(--red-600);
+ width: 16px;
+ align-items: center;
+ height: 16px;
+ font-size: 10px;
+ border-radius: 50%;
+}
+
+
+.cart-animate {
+ animation: wiggle 0.5s linear;
+}
+@keyframes wiggle {
+ 8%,
+ 41% {
+ transform: translateX(-10px);
+ }
+ 25%,
+ 58% {
+ transform: translate(10px);
+ }
+ 75% {
+ transform: translate(-5px);
+ }
+ 92% {
+ transform: translate(5px);
+ }
+ 0%,
+ 100% {
+ transform: translate(0);
+ }
+}
+
+.total-discount {
+ font-size: 14px;
+ color: var(--primary-color) !important;
+}
#page-cart {
.shopping-cart-header {
@@ -340,6 +627,7 @@ body.product-page {
display: flex;
flex-direction: column;
justify-content: space-between;
+ height: fit-content;
}
.cart-items-header {
@@ -347,6 +635,10 @@ body.product-page {
}
.cart-table {
+ tr {
+ margin-bottom: 1rem;
+ }
+
th, tr, td {
border-color: var(--border-color);
border-width: 1px;
@@ -364,71 +656,200 @@ body.product-page {
color: var(--text-color);
}
+ .cart-item-image {
+ width: 20%;
+ min-width: 100px;
+ img {
+ max-height: 112px;
+ }
+
+ .no-image-cart-item {
+ max-height: 112px;
+ display: flex; justify-content: center;
+ background-color: var(--gray-200);
+ align-items: center;
+ color: var(--gray-400);
+ margin-top: .15rem;
+ border-radius: 6px;
+ height: 100%;
+ font-size: 24px;
+ }
+ }
+
.cart-items {
.item-title {
- font-size: var(--text-base);
+ width: 80%;
+ font-size: 14px;
font-weight: 500;
color: var(--text-color);
}
.item-subtitle {
color: var(--text-muted);
- font-size: var(--text-md);
+ font-size: 13px;
}
.item-subtotal {
- font-size: var(--text-base);
+ font-size: 14px;
font-weight: 500;
}
+ .sm-item-subtotal {
+ font-size: 14px;
+ font-weight: 500;
+ display: none;
+
+ @media (max-width: 992px) {
+ display: unset !important;
+ }
+ }
+
.item-rate {
- font-size: var(--text-md);
+ font-size: 13px;
color: var(--text-muted);
}
- textarea {
- width: 40%;
+ .free-tag {
+ padding: 4px 8px;
+ border-radius: 4px;
+ background-color: var(--dark-green-50);
}
+
+ textarea {
+ width: 80%;
+ height: 60px;
+ font-size: 14px;
+ }
+
}
.cart-tax-items {
.item-grand-total {
font-size: 16px;
- font-weight: 600;
+ font-weight: 700;
color: var(--text-color);
}
}
+
+ .column-sm-view {
+ @media (max-width: 992px) {
+ display: none !important;
+ }
+ }
+
+ .item-column {
+ width: 50%;
+ @media (max-width: 992px) {
+ width: 70%;
+ }
+ }
+
+ .remove-cart-item {
+ border-radius: 6px;
+ border: 1px solid var(--gray-100);
+ width: 28px;
+ height: 28px;
+ font-weight: 300;
+ color: var(--gray-700);
+ background-color: var(--gray-100);
+ float: right;
+ cursor: pointer;
+ margin-top: .25rem;
+ justify-content: center;
+ }
+
+ .remove-cart-item-logo {
+ margin-top: 2px;
+ margin-left: 2.2px;
+ fill: var(--gray-700) !important;
+ }
}
- .cart-addresses {
+ .cart-payment-addresses {
hr {
border-color: var(--border-color);
}
}
+ .payment-summary {
+ h6 {
+ padding-bottom: 1rem;
+ border-bottom: solid 1px var(--gray-200);
+ }
+
+ table {
+ font-size: 14px;
+ td {
+ padding: 0;
+ padding-top: 0.35rem !important;
+ border: none !important;
+ }
+
+ &.grand-total {
+ border-top: solid 1px var(--gray-200);
+ }
+ }
+
+ .bill-label {
+ color: var(--gray-600);
+ }
+
+ .bill-content {
+ font-weight: 500;
+ &.net-total {
+ font-size: 16px;
+ font-weight: 600;
+ }
+ }
+
+ .btn-coupon-code {
+ font-size: 14px;
+ border: dashed 1px var(--gray-400);
+ box-shadow: none;
+ }
+ }
+
.number-spinner {
width: 75%;
+ min-width: 105px;
.cart-btn {
border: none;
background: var(--gray-100);
box-shadow: none;
+ width: 24px;
height: 28px;
align-items: center;
+ justify-content: center;
display: flex;
+ font-size: 20px;
+ font-weight: 300;
+ color: var(--gray-700);
}
.cart-qty {
height: 28px;
- font-size: var(--text-md);
+ font-size: 13px;
+ &:disabled {
+ background: var(--gray-100);
+ opacity: 0.65;
+ }
}
}
.place-order-container {
.btn-place-order {
- width: 62%;
+ float: right;
}
}
}
+
+ .t-and-c-container {
+ padding: 1.5rem;
+ }
+
+ .t-and-c-terms {
+ font-size: 14px;
+ }
}
.cart-empty.frappe-card {
@@ -444,7 +865,7 @@ body.product-page {
.address-card {
.card-title {
- font-size: var(--text-base);
+ font-size: 14px;
font-weight: 500;
}
@@ -453,27 +874,37 @@ body.product-page {
}
.card-text {
- font-size: var(--text-md);
+ font-size: 13px;
color: var(--gray-700);
}
.card-link {
- font-size: var(--text-md);
+ font-size: 13px;
svg use {
- stroke: var(--blue-500);
+ stroke: var(--primary-color);
}
}
.btn-change-address {
- color: var(--blue-500);
+ border: 1px solid var(--primary-color);
+ color: var(--primary-color);
+ box-shadow: none;
}
}
+.address-header {
+ margin-top: .15rem;padding: 0;
+}
+
+.btn-new-address {
+ float: right;
+ font-size: 15px !important;
+ color: var(--primary-color) !important;
+}
+
.btn-new-address:hover, .btn-change-address:hover {
- box-shadow: none;
- color: var(--blue-500) !important;
- border: 1px solid var(--blue-500);
+ color: var(--primary-color) !important;
}
.modal .address-card {
@@ -483,3 +914,451 @@ body.product-page {
border: 1px solid var(--dark-border-color);
}
}
+
+.cart-indicator {
+ position: absolute;
+ text-align: center;
+ width: 22px;
+ height: 22px;
+ left: calc(100% - 40px);
+ top: 22px;
+
+ border-radius: 66px;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ background: white;
+ color: var(--primary-color);
+ font-size: 14px;
+
+ &.list-indicator {
+ position: unset;
+ margin-left: auto;
+ }
+}
+
+
+.like-action {
+ visibility: hidden;
+ text-align: center;
+ position: absolute;
+ cursor: pointer;
+ width: 28px;
+ height: 28px;
+ left: 20px;
+ top: 20px;
+
+ /* White */
+ background: white;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ border-radius: 66px;
+
+ &.like-action-wished {
+ visibility: visible !important;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.like-action-list {
+ visibility: hidden;
+ text-align: center;
+ position: absolute;
+ cursor: pointer;
+ width: 28px;
+ height: 28px;
+ left: 20px;
+ top: 0;
+
+ /* White */
+ background: white;
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+ border-radius: 66px;
+
+ &.like-action-wished {
+ visibility: visible !important;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.like-action-item-fp {
+ visibility: visible !important;
+ position: unset;
+ float: right;
+}
+
+.like-animate {
+ animation: expand cubic-bezier(0.04, 0.4, 0.5, 0.95) 1.6s forwards 1;
+}
+
+@keyframes expand {
+ 30% {
+ transform: scale(1.3);
+ }
+ 50% {
+ transform: scale(0.8);
+ }
+ 70% {
+ transform: scale(1.1);
+ }
+ 100% {
+ transform: scale(1);
+ }
+ }
+
+.not-wished {
+ cursor: pointer;
+ stroke: #F47A7A !important;
+
+ &:hover {
+ fill: #F47A7A;
+ }
+}
+
+.wished {
+ stroke: none;
+ fill: #F47A7A !important;
+}
+
+.list-row-checkbox {
+ &:before {
+ display: none;
+ }
+
+ &:checked:before {
+ display: block;
+ z-index: 1;
+ }
+}
+
+#pay-for-order {
+ padding: .5rem 1rem; // Pay button in SO
+}
+
+.btn-explore-variants {
+ visibility: hidden;
+ box-shadow: none;
+ margin: var(--margin-sm) 0;
+ width: 90px;
+ max-height: 50px; // to avoid resizing on window resize
+ flex: none;
+ transition: 0.3s ease;
+
+ color: white;
+ background-color: var(--orange-500);
+ border: 1px solid var(--orange-500);
+ font-size: 13px;
+
+ &:hover {
+ color: white;
+ }
+}
+
+.btn-add-to-cart-list{
+ visibility: hidden;
+ box-shadow: none;
+ margin: var(--margin-sm) 0;
+ // margin-top: auto !important;
+ max-height: 50px; // to avoid resizing on window resize
+ flex: none;
+ transition: 0.3s ease;
+
+ font-size: 13px;
+
+ &:hover {
+ color: white;
+ }
+
+ @media (max-width: 992px) {
+ visibility: visible !important;
+ }
+}
+
+.go-to-cart-grid {
+ max-height: 30px;
+ margin-top: 1rem !important;
+}
+
+.go-to-cart {
+ max-height: 30px;
+ float: right;
+}
+
+.remove-wish {
+ background-color: white;
+ position: absolute;
+ cursor: pointer;
+ top:10px;
+ right: 20px;
+ width: 32px;
+ height: 32px;
+
+ border-radius: 50%;
+ border: 1px solid var(--gray-100);
+ box-shadow: 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 1px 4px rgba(17, 43, 66, 0.1);
+}
+
+.wish-removed {
+ display: none;
+}
+
+.item-website-specification {
+ font-size: .875rem;
+ .product-title {
+ font-size: 18px;
+ }
+
+ .table {
+ width: 70%;
+ }
+
+ td {
+ border: none !important;
+ }
+
+ .spec-label {
+ color: var(--gray-600);
+ }
+
+ .spec-content {
+ color: var(--gray-800);
+ }
+}
+
+.reviews-full-page {
+ padding: 1rem 2rem;
+}
+
+.ratings-reviews-section {
+ border-top: 1px solid #E2E6E9;
+ padding: .5rem 1rem;
+}
+
+.reviews-header {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--gray-800);
+ display: flex;
+ align-items: center;
+ padding: 0;
+}
+
+.btn-write-review {
+ float: right;
+ padding: .5rem 1rem;
+ font-size: 14px;
+ font-weight: 400;
+ border: none !important;
+ box-shadow: none;
+
+ color: var(--gray-900);
+ background-color: var(--gray-100);
+
+ &:hover {
+ box-shadow: var(--btn-shadow);
+ }
+}
+
+.btn-view-more {
+ font-size: 14px;
+}
+
+.rating-summary-section {
+ display: flex;
+}
+
+.rating-summary-title {
+ margin-top: 0.15rem;
+ font-size: 18px;
+}
+
+.rating-summary-numbers {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ border-right: solid 1px var(--gray-100);
+}
+
+.user-review-title {
+ margin-top: 0.15rem;
+ font-size: 15px;
+ font-weight: 600;
+}
+
+.rating {
+ --star-fill: var(--gray-300);
+ .star-hover {
+ --star-fill: var(--yellow-100);
+ }
+ .star-click {
+ --star-fill: var(--yellow-300);
+ }
+}
+
+.ratings-pill {
+ background-color: var(--gray-100);
+ padding: .5rem 1rem;
+ border-radius: 66px;
+}
+
+.review {
+ max-width: 80%;
+ line-height: 1.6;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid #E2E6E9;
+}
+
+.review-signature {
+ display: flex;
+ font-size: 13px;
+ color: var(--gray-500);
+ font-weight: 400;
+
+ .reviewer {
+ padding-right: 8px;
+ color: var(--gray-600);
+ }
+}
+
+.rating-progress-bar-section {
+ padding-bottom: 2rem;
+
+ .rating-bar-title {
+ margin-left: -15px;
+ }
+
+ .rating-progress-bar {
+ margin-bottom: 4px;
+ height: 7px;
+ margin-top: 6px;
+
+ .progress-bar-cosmetic {
+ background-color: var(--gray-600);
+ border-radius: var(--border-radius);
+ }
+ }
+}
+
+.offer-container {
+ font-size: 14px;
+}
+
+#search-results-container {
+ border: 1px solid var(--gray-200);
+ padding: .25rem 1rem;
+
+ .category-chip {
+ background-color: var(--gray-100);
+ border: none !important;
+ box-shadow: none;
+ }
+
+ .recent-search {
+ padding: .5rem .5rem;
+ border-radius: var(--border-radius);
+
+ &:hover {
+ background-color: var(--gray-100);
+ }
+ }
+}
+
+#search-box {
+ background-color: white;
+ height: 100%;
+ padding-left: 2.5rem;
+ border: 1px solid var(--gray-200);
+}
+
+.search-icon {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 2.5rem;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding-bottom: 1px;
+}
+
+#toggle-view {
+ float: right;
+
+ .btn-primary {
+ background-color: var(--gray-600);
+ box-shadow: 0 0 0 0.2rem var(--gray-400);
+ }
+}
+
+.placeholder-div {
+ height:80%;
+ width: -webkit-fill-available;
+ padding: 50px;
+ text-align: center;
+ background-color: #F9FAFA;
+ border-top-left-radius: calc(0.75rem - 1px);
+ border-top-right-radius: calc(0.75rem - 1px);
+}
+.placeholder {
+ font-size: 72px;
+}
+
+[data-path="cart"] {
+ .modal-backdrop {
+ background-color: var(--gray-50); // lighter backdrop only on cart freeze
+ }
+}
+
+.item-thumb {
+ height: 50px;
+ max-width: 80px;
+ min-width: 80px;
+ object-fit: cover;
+}
+
+.brand-line {
+ color: gray;
+}
+
+.btn-next, .btn-prev {
+ font-size: 14px;
+}
+
+.alert-error {
+ color: #e27a84;
+ background-color: #fff6f7;
+ border-color: #f5c6cb;
+}
+
+.font-md {
+ font-size: 14px !important;
+}
+
+.in-green {
+ color: var(--green-info) !important;
+ font-weight: 500;
+}
+
+.has-stock {
+ font-weight: 400 !important;
+}
+
+.out-of-stock {
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ color: #F47A7A;
+}
+
+.mt-minus-2 {
+ margin-top: -2rem;
+}
+
+.mt-minus-1 {
+ margin-top: -1rem;
+}
\ No newline at end of file
diff --git a/erpnext/quality_management/doctype/non_conformance/non_conformance.py b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
index d4e8cc7a716..a4613fdaf6b 100644
--- a/erpnext/quality_management/doctype/non_conformance/non_conformance.py
+++ b/erpnext/quality_management/doctype/non_conformance/non_conformance.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class NonConformance(Document):
pass
diff --git a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
index 54f8b58cfb0..759b117f9b0 100644
--- a/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
+++ b/erpnext/quality_management/doctype/non_conformance/test_non_conformance.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestNonConformance(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_action/quality_action.py b/erpnext/quality_management/doctype/quality_action/quality_action.py
index 02401ba689d..646a0dfc2c8 100644
--- a/erpnext/quality_management/doctype/quality_action/quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/quality_action.py
@@ -3,9 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class QualityAction(Document):
def validate(self):
self.status = 'Open' if any([d.status=='Open' for d in self.resolutions]) else 'Completed'
diff --git a/erpnext/quality_management/doctype/quality_action/test_quality_action.py b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
index 98d665f3910..33229d4b451 100644
--- a/erpnext/quality_management/doctype/quality_action/test_quality_action.py
+++ b/erpnext/quality_management/doctype/quality_action/test_quality_action.py
@@ -3,9 +3,9 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityAction(unittest.TestCase):
# quality action has no code
pass
diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
index de8873feb0c..b456fb7e9a0 100644
--- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
+++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityActionResolution(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
index d3e96cf2d94..9189c282973 100644
--- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class QualityFeedback(Document):
@frappe.whitelist()
def set_parameters(self):
diff --git a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
index 5a8bd5ce30c..7a87c362446 100644
--- a/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
+++ b/erpnext/quality_management/doctype/quality_feedback/test_quality_feedback.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
class TestQualityFeedback(unittest.TestCase):
def test_quality_feedback(self):
diff --git a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
index d652e8a57bb..9a21b263603 100644
--- a/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
+++ b/erpnext/quality_management/doctype/quality_feedback_parameter/quality_feedback_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackParameter(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
index 0c6dfc07802..c6a520a3c59 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackTemplate(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
index afed14b6ad0..1de58aae3ed 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template/test_quality_feedback_template.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityFeedbackTemplate(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
index 3f3348fd7fa..44a6b014a0c 100644
--- a/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
+++ b/erpnext/quality_management/doctype/quality_feedback_template_parameter/quality_feedback_template_parameter.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityFeedbackTemplateParameter(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_goal/quality_goal.py b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
index 3e616b75ceb..2888401782a 100644
--- a/erpnext/quality_management/doctype/quality_goal/quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/quality_goal.py
@@ -3,10 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QualityGoal(Document):
def validate(self):
pass
diff --git a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
index 0e135b50212..84240d227ea 100644
--- a/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
+++ b/erpnext/quality_management/doctype/quality_goal/test_quality_goal.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.quality_management.doctype.quality_procedure.test_quality_procedure import create_procedure
+
+import frappe
+
class TestQualityGoal(unittest.TestCase):
def test_quality_goal(self):
diff --git a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
index f4bd357f1b2..c9c2c6e564c 100644
--- a/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
+++ b/erpnext/quality_management/doctype/quality_goal_objective/quality_goal_objective.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityGoalObjective(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
index 9e453ebfc2e..0ac0484399e 100644
--- a/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/quality_meeting.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class QualityMeeting(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
index 6bf4c179c6b..e57256d2896 100644
--- a/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
+++ b/erpnext/quality_management/doctype/quality_meeting/test_quality_meeting.py
@@ -3,9 +3,9 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestQualityMeeting(unittest.TestCase):
# nothing to test
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
index 5d77975d74c..5e4d9ff37a7 100644
--- a/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
+++ b/erpnext/quality_management/doctype/quality_meeting_agenda/quality_meeting_agenda.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityMeetingAgenda(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
index 4750cc1f7af..8744d275ed8 100644
--- a/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
+++ b/erpnext/quality_management/doctype/quality_meeting_agenda/test_quality_meeting_agenda.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestQualityMeetingAgenda(unittest.TestCase):
pass
diff --git a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
index 47b2c95bd9e..e3d061b36ca 100644
--- a/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
+++ b/erpnext/quality_management/doctype/quality_meeting_minutes/quality_meeting_minutes.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityMeetingMinutes(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
index 117db0012ba..56293c98e09 100644
--- a/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/quality_procedure.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils.nestedset import NestedSet, rebuild_tree
from frappe import _
+from frappe.utils.nestedset import NestedSet
+
class QualityProcedure(NestedSet):
nsm_parent_field = 'parent_quality_procedure'
diff --git a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
index 4fa7734bc68..b064011bf6c 100644
--- a/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
+++ b/erpnext/quality_management/doctype/quality_procedure/test_quality_procedure.py
@@ -3,11 +3,13 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
from .quality_procedure import add_node
+
class TestQualityProcedure(unittest.TestCase):
def test_add_node(self):
try:
diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
index 0d9a286052d..e281294643d 100644
--- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
+++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityProcedureProcess(Document):
pass
diff --git a/erpnext/quality_management/doctype/quality_review/quality_review.py b/erpnext/quality_management/doctype/quality_review/quality_review.py
index 34cc890e219..b766623510a 100644
--- a/erpnext/quality_management/doctype/quality_review/quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/quality_review.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class QualityReview(Document):
def validate(self):
# fetch targets from goal
diff --git a/erpnext/quality_management/doctype/quality_review/test_quality_review.py b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
index 161ecd01ef1..2f28ddac45e 100644
--- a/erpnext/quality_management/doctype/quality_review/test_quality_review.py
+++ b/erpnext/quality_management/doctype/quality_review/test_quality_review.py
@@ -3,12 +3,14 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
from ..quality_goal.test_quality_goal import get_quality_goal
from .quality_review import review
+
class TestQualityReview(unittest.TestCase):
def test_review_creation(self):
quality_goal = get_quality_goal()
diff --git a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
index 3092a1e9979..23b11e87e6a 100644
--- a/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
+++ b/erpnext/quality_management/doctype/quality_review_objective/quality_review_objective.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QualityReviewObjective(Document):
pass
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index faa59129a5a..45a689efa8b 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
from erpnext import get_region
+
def check_deletion_permission(doc, method):
region = get_region(doc.company)
if region in ["Nepal", "France"] and doc.docstatus != 0:
diff --git a/erpnext/regional/address_template/setup.py b/erpnext/regional/address_template/setup.py
index 1b4087d77ba..0f9a1b19f53 100644
--- a/erpnext/regional/address_template/setup.py
+++ b/erpnext/regional/address_template/setup.py
@@ -1,7 +1,9 @@
"""Import Address Templates from ./templates directory."""
import os
+
import frappe
+
def set_up_address_templates(default_country=None):
for country, html in get_address_templates():
is_default = 1 if country == default_country else 0
diff --git a/erpnext/regional/address_template/test_regional_address_template.py b/erpnext/regional/address_template/test_regional_address_template.py
index 8a05ea26f45..2880d6253f9 100644
--- a/erpnext/regional/address_template/test_regional_address_template.py
+++ b/erpnext/regional/address_template/test_regional_address_template.py
@@ -1,9 +1,11 @@
from __future__ import unicode_literals
+
from unittest import TestCase
import frappe
-from erpnext.regional.address_template.setup import get_address_templates
-from erpnext.regional.address_template.setup import update_address_template
+
+from erpnext.regional.address_template.setup import get_address_templates, update_address_template
+
def ensure_country(country):
if frappe.db.exists("Country", country):
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.py b/erpnext/regional/doctype/datev_settings/datev_settings.py
index cff5bba58fd..0d2d9eb4b47 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.py
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class DATEVSettings(Document):
pass
diff --git a/erpnext/regional/doctype/datev_settings/test_datev_settings.py b/erpnext/regional/doctype/datev_settings/test_datev_settings.py
index 0271329f4d2..73412f755d7 100644
--- a/erpnext/regional/doctype/datev_settings/test_datev_settings.py
+++ b/erpnext/regional/doctype/datev_settings/test_datev_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestDATEVSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
index 9150bdd9260..38fe3089412 100644
--- a/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
+++ b/erpnext/regional/doctype/e_invoice_request_log/e_invoice_request_log.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EInvoiceRequestLog(Document):
pass
diff --git a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
index c84e9a249bd..091cc88e454 100644
--- a/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
+++ b/erpnext/regional/doctype/e_invoice_request_log/test_e_invoice_request_log.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestEInvoiceRequestLog(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
index 4f6b3eca7a6..70ec2ed0679 100644
--- a/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/e_invoice_settings.py
@@ -7,6 +7,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
+
class EInvoiceSettings(Document):
def validate(self):
if self.enable and not self.credentials:
diff --git a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
index a11ce63ee6c..10770deb0ee 100644
--- a/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
+++ b/erpnext/regional/doctype/e_invoice_settings/test_e_invoice_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestEInvoiceSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
index 056c54f069d..a0fe399f110 100644
--- a/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
+++ b/erpnext/regional/doctype/e_invoice_user/e_invoice_user.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EInvoiceUser(Document):
pass
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
index 4791dc26753..0704de8387f 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class GSTHSNCode(Document):
pass
diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
deleted file mode 100644
index 24c5fd355ff..00000000000
--- a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GST HSN Code", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GST HSN Code
- () => frappe.tests.make('GST HSN Code', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
index ed54f207139..1a90e6d711c 100644
--- a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGSTHSNCode(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.py b/erpnext/regional/doctype/gst_settings/gst_settings.py
index af3d92e59a7..7b27fb6c5bc 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.py
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.py
@@ -3,11 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, os
+
+import os
+
+import frappe
from frappe import _
-from frappe.utils import get_url, nowdate, date_diff
-from frappe.model.document import Document
from frappe.contacts.doctype.contact.contact import get_default_contact
+from frappe.model.document import Document
+from frappe.utils import date_diff, get_url, nowdate
+
class EmailMissing(frappe.ValidationError): pass
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.js b/erpnext/regional/doctype/gst_settings/test_gst_settings.js
deleted file mode 100644
index 00fcca6f326..00000000000
--- a/erpnext/regional/doctype/gst_settings/test_gst_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: GST Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new GST Settings
- () => frappe.tests.make('GST Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.py b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
index d118dee6177..836d3a88c33 100644
--- a/erpnext/regional/doctype/gst_settings/test_gst_settings.py
+++ b/erpnext/regional/doctype/gst_settings/test_gst_settings.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGSTSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 0ee5b097b54..d8ce3197395 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -3,15 +3,19 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import os
+
import json
+import os
+
import frappe
-from six import iteritems
from frappe import _
from frappe.model.document import Document
-from frappe.utils import flt, cstr
+from frappe.utils import cstr, flt
+from six import iteritems
+
from erpnext.regional.india import state_numbers
+
class GSTR3BReport(Document):
def validate(self):
self.get_data()
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index 065f80d610a..115f9b88165 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -3,13 +3,15 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
-from frappe.utils import getdate
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-from erpnext.stock.doctype.item.test_item import make_item
import json
+import unittest
+
+import frappe
+from frappe.utils import getdate
+
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.stock.doctype.item.test_item import make_item
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
index 00300539e9a..76cb621f541 100644
--- a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
@@ -3,21 +3,21 @@
from __future__ import unicode_literals
-from decimal import Decimal
-import json
import re
-import traceback
import zipfile
-import frappe, erpnext
+
+import dateutil
+import frappe
+from bs4 import BeautifulSoup as bs
from frappe import _
from frappe.model.document import Document
-from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.utils import flt, get_datetime_str, today
from frappe.utils.data import format_datetime
-from bs4 import BeautifulSoup as bs
-from frappe.utils import cint, flt, today, nowdate, add_days, get_files_path, get_datetime_str
-import dateutil
from frappe.utils.file_manager import save_file
+import erpnext
+
+
class ImportSupplierInvoice(Document):
def validate(self):
if not frappe.db.get_value("Stock Settings", fieldname="stock_uom"):
diff --git a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
index d1caf77fc2c..4be4c3a22f9 100644
--- a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
+++ b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestImportSupplierInvoice(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
index 656c3296e58..d8553f1d913 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import getdate, get_link_to_form
from frappe.model.document import Document
+from frappe.utils import get_link_to_form, getdate
+
from erpnext.accounts.utils import get_fiscal_year
+
class LowerDeductionCertificate(Document):
def validate(self):
self.validate_dates()
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
index 7e950206fcc..54443c0206a 100644
--- a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
+++ b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestLowerDeductionCertificate(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/product_tax_category/__init__.py b/erpnext/regional/doctype/product_tax_category/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.js b/erpnext/regional/doctype/product_tax_category/product_tax_category.js
new file mode 100644
index 00000000000..9f8e7950156
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Product Tax Category', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.json b/erpnext/regional/doctype/product_tax_category/product_tax_category.json
new file mode 100644
index 00000000000..147cb34425d
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.json
@@ -0,0 +1,70 @@
+{
+ "actions": [],
+ "autoname": "field:product_tax_code",
+ "creation": "2021-08-23 12:33:37.910225",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "product_tax_code",
+ "column_break_2",
+ "category_name",
+ "section_break_4",
+ "description"
+ ],
+ "fields": [
+ {
+ "fieldname": "product_tax_code",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Product Tax Code",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ },
+ {
+ "fieldname": "category_name",
+ "fieldtype": "Data",
+ "label": "Category Name",
+ "length": 255
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-08-24 09:10:25.313642",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Product Tax Category",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "category_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/product_tax_category/product_tax_category.py b/erpnext/regional/doctype/product_tax_category/product_tax_category.py
new file mode 100644
index 00000000000..b6be9e0920b
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/product_tax_category.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class ProductTaxCategory(Document):
+ pass
diff --git a/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py b/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py
new file mode 100644
index 00000000000..2668f2391af
--- /dev/null
+++ b/erpnext/regional/doctype/product_tax_category/test_product_tax_category.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestProductTaxCategory(unittest.TestCase):
+ pass
diff --git a/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py b/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
index d74154bfe78..4c3e8a78e9d 100644
--- a/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
+++ b/erpnext/regional/doctype/south_africa_vat_settings/south_africa_vat_settings.py
@@ -4,5 +4,6 @@
# import frappe
from frappe.model.document import Document
+
class SouthAfricaVATSettings(Document):
pass
diff --git a/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py b/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
index 1c36652ad6e..0f19f25f88d 100644
--- a/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
+++ b/erpnext/regional/doctype/south_africa_vat_settings/test_south_africa_vat_settings.py
@@ -4,5 +4,6 @@
# import frappe
import unittest
+
class TestSouthAfricaVATSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
index 41a0f1193bc..64b2ec5646c 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/tax_exemption_80g_certificate.py
@@ -3,12 +3,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.model.document import Document
-from frappe.utils import getdate, flt, get_link_to_form
-from erpnext.accounts.utils import get_fiscal_year
from frappe.contacts.doctype.address.address import get_company_address
+from frappe.model.document import Document
+from frappe.utils import flt, get_link_to_form, getdate
+
+from erpnext.accounts.utils import get_fiscal_year
+
class TaxExemption80GCertificate(Document):
def validate(self):
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
index 41b42036687..74e9ced3941 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate/test_tax_exemption_80g_certificate.py
@@ -3,14 +3,21 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
from frappe.utils import getdate
+
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.non_profit.doctype.donation.test_donation import create_donor, create_mode_of_payment, create_donor_type
from erpnext.non_profit.doctype.donation.donation import create_donation
-from erpnext.non_profit.doctype.membership.test_membership import setup_membership, make_membership
+from erpnext.non_profit.doctype.donation.test_donation import (
+ create_donor,
+ create_donor_type,
+ create_mode_of_payment,
+)
from erpnext.non_profit.doctype.member.member import create_member
+from erpnext.non_profit.doctype.membership.test_membership import make_membership, setup_membership
+
class TestTaxExemption80GCertificate(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
index bdad798d980..76d8912b004 100644
--- a/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
+++ b/erpnext/regional/doctype/tax_exemption_80g_certificate_detail/tax_exemption_80g_certificate_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TaxExemption80GCertificateDetail(Document):
pass
diff --git a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
index 80d6b3a5f1f..a1b27d7e3d3 100644
--- a/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
+++ b/erpnext/regional/doctype/uae_vat_account/uae_vat_account.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class UAEVATAccount(Document):
pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
index b88439f9b85..cec30e61cef 100644
--- a/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
+++ b/erpnext/regional/doctype/uae_vat_settings/test_uae_vat_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestUAEVATSettings(unittest.TestCase):
pass
diff --git a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
index 20dc604510b..1bf37dd499d 100644
--- a/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
+++ b/erpnext/regional/doctype/uae_vat_settings/uae_vat_settings.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class UAEVATSettings(Document):
pass
diff --git a/erpnext/regional/france/setup.py b/erpnext/regional/france/setup.py
index db6419e9462..3e3a9f6e56a 100644
--- a/erpnext/regional/france/setup.py
+++ b/erpnext/regional/france/setup.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def setup(company=None, patch=True):
make_custom_fields()
add_custom_roles_for_reports()
diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py
index 424615dbbc0..63c5a1f583b 100644
--- a/erpnext/regional/france/utils.py
+++ b/erpnext/regional/france/utils.py
@@ -2,7 +2,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
# don't remove this function it is used in tests
def test_method():
diff --git a/erpnext/regional/germany/setup.py b/erpnext/regional/germany/setup.py
index c1fa6e492d1..35d14135ba5 100644
--- a/erpnext/regional/germany/setup.py
+++ b/erpnext/regional/germany/setup.py
@@ -1,4 +1,4 @@
-import os
+
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index c5c2bc41f4d..9d1fabbada7 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -4,12 +4,12 @@ from __future__ import unicode_literals
import datetime
import zipfile
from csv import QUOTE_NONNUMERIC
-from six import BytesIO
-import six
import frappe
import pandas as pd
from frappe import _
+from six import BytesIO
+
from .datev_constants import DataCategory
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index faeb36fc693..5c4d30881d1 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from six import iteritems
states = [
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index fe4c172e237..19699243f9e 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -3,24 +3,39 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
+import base64
+import io
+import json
import os
import re
-import jwt
import sys
-import json
-import base64
-import frappe
-import six
import traceback
-import io
+
+import frappe
+import jwt
+import six
from frappe import _, bold
-from pyqrcode import create as qrcreate
-from frappe.utils.background_jobs import enqueue
-from frappe.utils.scheduler import is_scheduler_inactive
from frappe.core.page.background_jobs.background_jobs import get_info
-from frappe.integrations.utils import make_post_request, make_get_request
+from frappe.integrations.utils import make_get_request, make_post_request
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.data import (
+ add_to_date,
+ cint,
+ cstr,
+ flt,
+ format_date,
+ get_link_to_form,
+ getdate,
+ now_datetime,
+ time_diff_in_hours,
+ time_diff_in_seconds,
+)
+from frappe.utils.scheduler import is_scheduler_inactive
+from pyqrcode import create as qrcreate
+
from erpnext.regional.india.utils import get_gst_accounts, get_place_of_supply
-from frappe.utils.data import cstr, cint, format_date, flt, time_diff_in_seconds, now_datetime, add_to_date, get_link_to_form, getdate, time_diff_in_hours
+
@frappe.whitelist()
def validate_eligibility(doc):
@@ -483,7 +498,7 @@ def log_error(data=None):
"Data:", data, seperator,
"Exception:", err_tb
])
- frappe.log_error(title=_('E Invoice Request Failed'), message=message)
+ return frappe.log_error(title=_('E Invoice Request Failed'), message=message)
def santize_einvoice_fields(einvoice):
int_fields = ["Pin","Distance","CrDay"]
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 2d6b9133900..888dcfc7bd7 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -3,14 +3,19 @@
from __future__ import unicode_literals
-import frappe, os, json
+import json
+import os
+
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.permissions import add_permission, update_permission_property
-from erpnext.regional.india import states
-from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
from frappe.utils import today
+from erpnext.accounts.utils import FiscalYearError, get_fiscal_year
+from erpnext.regional.india import states
+
+
def setup(company=None, patch=True):
# Company independent fixtures should be called only once at the first company setup
if frappe.db.count('Company', {'country': 'India'}) <=1:
@@ -492,6 +497,26 @@ def make_custom_fields(update=True):
hidden=1, insert_after='einvoice_status', no_copy=1, print_hide=1, read_only=1)
]
+ payment_entry_fields = [
+ dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', insert_after='deductions',
+ print_hide=1, collapsible=1),
+ dict(fieldname='company_address', label='Company Address', fieldtype='Link', insert_after='gst_section',
+ print_hide=1, options='Address'),
+ dict(fieldname='company_gstin', label='Company GSTIN',
+ fieldtype='Data', insert_after='company_address',
+ fetch_from='company_address.gstin', print_hide=1, read_only=1),
+ dict(fieldname='place_of_supply', label='Place of Supply',
+ fieldtype='Data', insert_after='company_gstin',
+ print_hide=1, read_only=1),
+ dict(fieldname='gst_column_break', fieldtype='Column Break',
+ insert_after='place_of_supply'),
+ dict(fieldname='customer_address', label='Customer Address', fieldtype='Link', insert_after='gst_column_break',
+ print_hide=1, options='Address', depends_on = 'eval:doc.party_type == "Customer"'),
+ dict(fieldname='customer_gstin', label='Customer GSTIN',
+ fieldtype='Data', insert_after='customer_address',
+ fetch_from='customer_address.gstin', print_hide=1, read_only=1)
+ ]
+
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -506,6 +531,7 @@ def make_custom_fields(update=True):
'Purchase Receipt': purchase_invoice_gst_fields,
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields + si_einvoice_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields + delivery_note_gst_category,
+ 'Payment Entry': payment_entry_fields,
'Journal Entry': journal_entry_fields,
'Sales Order': sales_invoice_gst_fields,
'Tax Category': inter_state_gst_field,
diff --git a/erpnext/regional/india/test_utils.py b/erpnext/regional/india/test_utils.py
index a16f56c704a..2c77c8d8aa8 100644
--- a/erpnext/regional/india/test_utils.py
+++ b/erpnext/regional/india/test_utils.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
import unittest
-import frappe
from unittest.mock import patch
+
+import frappe
+
from erpnext.regional.india.utils import validate_document_name
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index ce5aa10902e..0feb2dbe536 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -1,19 +1,19 @@
from __future__ import unicode_literals
-import frappe, re, json
+
+import json
+import re
+
+import frappe
from frappe import _
-import erpnext
-from frappe.utils import cstr, flt, cint, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words, getdate
-from erpnext.regional.india import states, state_numbers
-from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
+from frappe.model.utils import get_fetch_values
+from frappe.utils import cint, cstr, date_diff, flt, getdate, nowdate
+from six import string_types
+
from erpnext.controllers.accounts_controller import get_taxes_and_charges
+from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
from erpnext.hr.utils import get_salary_assignment
from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip
-from erpnext.regional.india import number_state_mapping
-from six import string_types
-from erpnext.accounts.general_ledger import make_gl_entries
-from erpnext.accounts.utils import get_account_currency
-from frappe.model.utils import get_fetch_values
-
+from erpnext.regional.india import number_state_mapping, state_numbers, states
GST_INVOICE_NUMBER_FORMAT = re.compile(r"^[a-zA-Z0-9\-/]+$") #alphanumeric and - /
GSTIN_FORMAT = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
@@ -767,6 +767,15 @@ def update_itc_availed_fields(doc, method):
if tax.account_head in gst_accounts.get('cess_account', []):
doc.itc_cess_amount += flt(tax.base_tax_amount_after_discount_amount)
+def update_place_of_supply(doc, method):
+ country = frappe.get_cached_value('Company', doc.company, 'country')
+ if country != 'India':
+ return
+
+ address = frappe.db.get_value("Address", doc.get('customer_address'), ["gst_state", "gst_state_number"], as_dict=1)
+ if address and address.gst_state and address.gst_state_number:
+ doc.place_of_supply = cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
+
@frappe.whitelist()
def get_regional_round_off_accounts(company, account_list):
country = frappe.get_cached_value('Company', company, 'country')
diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py
index 7db2f6b0f8d..291906af9cd 100644
--- a/erpnext/regional/italy/setup.py
+++ b/erpnext/regional/italy/setup.py
@@ -8,7 +8,14 @@ import frappe
from frappe import _
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
-from erpnext.regional.italy import fiscal_regimes, tax_exemption_reasons, mode_of_payment_codes, vat_collectability_options
+
+from erpnext.regional.italy import (
+ fiscal_regimes,
+ mode_of_payment_codes,
+ tax_exemption_reasons,
+ vat_collectability_options,
+)
+
def setup(company=None, patch=True):
make_custom_fields()
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index ba1aeafc3e9..d6c7f1dbfa9 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -2,13 +2,14 @@ from __future__ import unicode_literals
import io
import json
+
import frappe
-from frappe.utils import flt, cstr
-from erpnext.controllers.taxes_and_totals import get_itemised_tax
from frappe import _
-from frappe.core.doctype.file.file import remove_file
+from frappe.utils import cstr, flt
+from frappe.utils.file_manager import remove_file
from six import string_types
-from frappe.desk.form.load import get_attachments
+
+from erpnext.controllers.taxes_and_totals import get_itemised_tax
from erpnext.regional.italy import state_codes
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index 8f077e3de0b..dcabe368aa5 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -10,13 +10,18 @@ Provide a report and downloadable CSV according to the German DATEV format.
from __future__ import unicode_literals
import json
+
import frappe
+from frappe import _
from six import string_types
-from frappe import _
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.regional.germany.utils.datev.datev_csv import zip_and_download, get_datev_csv
-from erpnext.regional.germany.utils.datev.datev_constants import Transactions, DebtorsCreditors, AccountNames
+from erpnext.regional.germany.utils.datev.datev_constants import (
+ AccountNames,
+ DebtorsCreditors,
+ Transactions,
+)
+from erpnext.regional.germany.utils.datev.datev_csv import get_datev_csv, zip_and_download
COLUMNS = [
{
@@ -200,7 +205,7 @@ def get_transactions(filters, as_dict=1):
def run(params_method, filters):
extra_fields, extra_joins, extra_filters = params_method(filters)
return run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=as_dict)
-
+
def sort_by(row):
# "Belegdatum" is in the fifth column when list format is used
return row["Belegdatum" if as_dict else 5]
@@ -361,7 +366,7 @@ def run_query(filters, extra_fields, extra_joins, extra_filters, as_dict=1):
FROM `tabGL Entry` gl
/* Kontonummer */
- LEFT JOIN `tabAccount` acc
+ LEFT JOIN `tabAccount` acc
ON gl.account = acc.name
LEFT JOIN `tabParty Account` par
diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py
index 59b878e94a5..b53889366f1 100644
--- a/erpnext/regional/report/datev/test_datev.py
+++ b/erpnext/regional/report/datev/test_datev.py
@@ -2,21 +2,27 @@
from __future__ import unicode_literals
import zipfile
-import frappe
-from six import BytesIO
from unittest import TestCase
-from frappe.utils import today, now_datetime, cstr
+
+import frappe
+from frappe.utils import cstr, now_datetime, today
+from six import BytesIO
+
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-
-from erpnext.regional.report.datev.datev import validate
-from erpnext.regional.report.datev.datev import get_transactions
-from erpnext.regional.report.datev.datev import get_customers
-from erpnext.regional.report.datev.datev import get_suppliers
-from erpnext.regional.report.datev.datev import get_account_names
-from erpnext.regional.report.datev.datev import download_datev_csv
-
+from erpnext.regional.germany.utils.datev.datev_constants import (
+ AccountNames,
+ DebtorsCreditors,
+ Transactions,
+)
from erpnext.regional.germany.utils.datev.datev_csv import get_datev_csv, get_header
-from erpnext.regional.germany.utils.datev.datev_constants import Transactions, DebtorsCreditors, AccountNames
+from erpnext.regional.report.datev.datev import (
+ download_datev_csv,
+ get_account_names,
+ get_customers,
+ get_suppliers,
+ get_transactions,
+)
+
def make_company(company_name, abbr):
if not frappe.db.exists("Company", company_name):
diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
index 66ffceae539..a068a380776 100644
--- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
+++ b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
validate_filters(filters)
diff --git a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
index 376ba3ee471..f4ce7a77ad9 100644
--- a/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
+++ b/erpnext/regional/report/electronic_invoice_register/electronic_invoice_register.py
@@ -2,7 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from erpnext.accounts.report.sales_register.sales_register import _execute
+
def execute(filters=None):
return _execute(filters)
diff --git a/erpnext/regional/report/eway_bill/eway_bill.py b/erpnext/regional/report/eway_bill/eway_bill.py
index 4f777fcf7e3..c78084f7dff 100644
--- a/erpnext/regional/report/eway_bill/eway_bill.py
+++ b/erpnext/regional/report/eway_bill/eway_bill.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
import re
+
+import frappe
from frappe import _
from frappe.utils import nowdate
+
def execute(filters=None):
if not filters: filters.setdefault('posting_date', [nowdate(), nowdate()])
columns, data = [], []
@@ -41,7 +44,7 @@ def get_data(filters):
}
# Regular expression set to remove all the special characters
- special_characters = "[$%^*()+\\[\]{};':\"\\|<>.?]"
+ special_characters = r"[$%^*()+\\[\]{};':\"\\|<>.?]"
for row in data:
set_defaults(row)
diff --git a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
index e903c9f00a4..9567916cd2a 100644
--- a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
+++ b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import format_datetime
-from frappe import _
+
import re
+import frappe
+from frappe import _
+from frappe.utils import format_datetime
+
+
def execute(filters=None):
account_details = {}
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
@@ -116,7 +119,7 @@ def get_result_as_list(data, filters):
if d.get("voucher_no").startswith("{0}-".format(JournalCode)) or d.get("voucher_no").startswith("{0}/".format(JournalCode)):
EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
else:
- EcritureNum = re.search("{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
+ EcritureNum = re.search(r"{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
EcritureDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")
diff --git a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
index b5948f9952d..092f72adf15 100644
--- a/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
+++ b/erpnext/regional/report/gst_itemised_purchase_register/gst_itemised_purchase_register.py
@@ -3,7 +3,10 @@
from __future__ import unicode_literals
-from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import _execute
+from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_register import (
+ _execute,
+)
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
index e13f509f475..44f623bfae9 100644
--- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
+++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
diff --git a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
index 12e9676b4ba..e9724441b17 100644
--- a/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
+++ b/erpnext/regional/report/gst_purchase_register/gst_purchase_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.purchase_register.purchase_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', fieldname="supplier_gstin", width=120),
diff --git a/erpnext/regional/report/gst_sales_register/gst_sales_register.py b/erpnext/regional/report/gst_sales_register/gst_sales_register.py
index 075bd483cf0..6975af35854 100644
--- a/erpnext/regional/report/gst_sales_register/gst_sales_register.py
+++ b/erpnext/regional/report/gst_sales_register/gst_sales_register.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
from erpnext.accounts.report.sales_register.sales_register import _execute
+
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
index 444f5dbb8ca..ef2bdb67980 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -51,7 +51,9 @@ frappe.query_reports["GSTR-1"] = {
{ "value": "B2C Large", "label": __("B2C(Large) Invoices - 5A, 5B") },
{ "value": "B2C Small", "label": __("B2C(Small) Invoices - 7") },
{ "value": "CDNR-REG", "label": __("Credit/Debit Notes (Registered) - 9B") },
- { "value": "EXPORT", "label": __("Export Invoice - 6A") }
+ { "value": "CDNR-UNREG", "label": __("Credit/Debit Notes (Unregistered) - 9B") },
+ { "value": "EXPORT", "label": __("Export Invoice - 6A") },
+ { "value": "Advances", "label": __("Tax Liability (Advances Received) - 11A(1), 11A(2)") }
],
"default": "B2B"
}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 9d4f9206f50..ca0defa648a 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -2,14 +2,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe import _
-from frappe.utils import flt, formatdate, now_datetime, getdate
+
+import json
from datetime import date
+
+import frappe
+from frappe import _
+from frappe.utils import flt, formatdate, getdate
from six import iteritems
-from erpnext.regional.doctype.gstr_3b_report.gstr_3b_report import get_period
+
from erpnext.regional.india.utils import get_gst_accounts
+
def execute(filters=None):
return Gstr1Report(filters).run()
@@ -50,26 +54,45 @@ class Gstr1Report(object):
self.get_invoice_items()
self.get_items_based_on_tax_rate()
self.invoice_fields = [d["fieldname"] for d in self.invoice_columns]
- self.get_data()
+
+ self.get_data()
return self.columns, self.data
def get_data(self):
if self.filters.get("type_of_business") in ("B2C Small", "B2C Large"):
self.get_b2c_data()
- else:
+ elif self.filters.get("type_of_business") == "Advances":
+ self.get_advance_data()
+ elif self.invoices:
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
for rate, items in items_based_on_rate.items():
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
- if self.filters.get("type_of_business") == "CDNR-REG":
+ if self.filters.get("type_of_business") in ("CDNR-REG", "CDNR-UNREG"):
row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
row.append("C" if invoice_details.is_return else "D")
if taxable_value:
self.data.append(row)
+ def get_advance_data(self):
+ advances_data = {}
+ advances = self.get_advance_entries()
+ for entry in advances:
+ # only consider IGST and SGST so as to avoid duplication of taxable amount
+ if entry.account_head in self.gst_accounts.igst_account or \
+ entry.account_head in self.gst_accounts.sgst_account:
+ advances_data.setdefault((entry.place_of_supply, entry.rate), [0.0, 0.0])
+ advances_data[(entry.place_of_supply, entry.rate)][0] += (entry.amount * 100 / entry.rate)
+ elif entry.account_head in self.gst_accounts.cess_account:
+ advances_data[(entry.place_of_supply, entry.rate)][1] += entry.amount
+
+ for key, value in advances_data.items():
+ row= [key[0], key[1], value[0], value[1]]
+ self.data.append(row)
+
def get_b2c_data(self):
b2cs_output = {}
@@ -106,7 +129,7 @@ class Gstr1Report(object):
def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
row = []
for fieldname in self.invoice_fields:
- if self.filters.get("type_of_business") == "CDNR-REG" and fieldname == "invoice_value":
+ if self.filters.get("type_of_business") in ("CDNR-REG", "CDNR-UNREG") and fieldname == "invoice_value":
row.append(abs(invoice_details.base_rounded_total) or abs(invoice_details.base_grand_total))
elif fieldname == "invoice_value":
row.append(invoice_details.base_rounded_total or invoice_details.base_grand_total)
@@ -167,6 +190,16 @@ class Gstr1Report(object):
for d in invoice_data:
self.invoices.setdefault(d.invoice_number, d)
+ def get_advance_entries(self):
+ return frappe.db.sql("""
+ SELECT SUM(a.base_tax_amount) as amount, a.account_head, a.rate, p.place_of_supply
+ FROM `tabPayment Entry` p, `tabAdvance Taxes and Charges` a
+ WHERE p.docstatus = 1
+ AND p.name = a.parent
+ AND posting_date between %s and %s
+ GROUP BY a.account_head, p.place_of_supply, a.rate
+ """, (self.filters.get('from_date'), self.filters.get('to_date')), as_dict=1)
+
def get_conditions(self):
conditions = ""
@@ -198,6 +231,12 @@ class Gstr1Report(object):
elif self.filters.get("type_of_business") == "CDNR-REG":
conditions += """ AND (is_return = 1 OR is_debit_note = 1) AND IFNULL(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ')"""
+ elif self.filters.get("type_of_business") == "CDNR-UNREG":
+ b2c_limit = frappe.db.get_single_value('GST Settings', 'b2c_limit')
+ conditions += """ AND ifnull(SUBSTR(place_of_supply, 1, 2),'') != ifnull(SUBSTR(company_gstin, 1, 2),'')
+ AND ABS(grand_total) > {0} AND (is_return = 1 OR is_debit_note = 1)
+ AND IFNULL(gst_category, '') in ('Unregistered', 'Overseas')""".format(flt(b2c_limit))
+
elif self.filters.get("type_of_business") == "EXPORT":
conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
@@ -503,6 +542,84 @@ class Gstr1Report(object):
"width": 80
}
]
+ elif self.filters.get("type_of_business") == "CDNR-UNREG":
+ self.invoice_columns = [
+ {
+ "fieldname": "customer_name",
+ "label": "Receiver Name",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "fieldname": "return_against",
+ "label": "Issued Against",
+ "fieldtype": "Link",
+ "options": "Sales Invoice",
+ "width": 120
+ },
+ {
+ "fieldname": "posting_date",
+ "label": "Note Date",
+ "fieldtype": "Date",
+ "width": 120
+ },
+ {
+ "fieldname": "invoice_number",
+ "label": "Note Number",
+ "fieldtype": "Link",
+ "options": "Sales Invoice",
+ "width":120
+ },
+ {
+ "fieldname": "export_type",
+ "label": "Export Type",
+ "fieldtype": "Data",
+ "hidden": 1
+ },
+ {
+ "fieldname": "reason_for_issuing_document",
+ "label": "Reason For Issuing document",
+ "fieldtype": "Data",
+ "width": 140
+ },
+ {
+ "fieldname": "place_of_supply",
+ "label": "Place Of Supply",
+ "fieldtype": "Data",
+ "width": 120
+ },
+ {
+ "fieldname": "gst_category",
+ "label": "GST Category",
+ "fieldtype": "Data"
+ },
+ {
+ "fieldname": "invoice_value",
+ "label": "Invoice Value",
+ "fieldtype": "Currency",
+ "width": 120
+ }
+ ]
+ self.other_columns = [
+ {
+ "fieldname": "cess_amount",
+ "label": "Cess Amount",
+ "fieldtype": "Currency",
+ "width": 100
+ },
+ {
+ "fieldname": "pre_gst",
+ "label": "PRE GST",
+ "fieldtype": "Data",
+ "width": 80
+ },
+ {
+ "fieldname": "document_type",
+ "label": "Document Type",
+ "fieldtype": "Data",
+ "width": 80
+ }
+ ]
elif self.filters.get("type_of_business") == "B2C Small":
self.invoice_columns = [
{
@@ -578,6 +695,25 @@ class Gstr1Report(object):
"width": 120
}
]
+ elif self.filters.get("type_of_business") == "Advances":
+ self.invoice_columns = [
+ {
+ "fieldname": "place_of_supply",
+ "label": "Place Of Supply",
+ "fieldtype": "Data",
+ "width": 120
+ }
+ ]
+
+ self.other_columns = [
+ {
+ "fieldname": "cess_amount",
+ "label": "Cess Amount",
+ "fieldtype": "Currency",
+ "width": 100
+ }
+ ]
+
self.columns = self.invoice_columns + self.tax_columns + self.other_columns
@frappe.whitelist()
@@ -616,12 +752,29 @@ def get_json(filters, report_name, data):
out = get_export_json(res)
gst_json["exp"] = out
- elif filters["type_of_business"] == 'CDNR-REG':
+ elif filters["type_of_business"] == "CDNR-REG":
for item in report_data[:-1]:
res.setdefault(item["customer_gstin"], {}).setdefault(item["invoice_number"],[]).append(item)
out = get_cdnr_reg_json(res, gstin)
gst_json["cdnr"] = out
+ elif filters["type_of_business"] == "CDNR-UNREG":
+ for item in report_data[:-1]:
+ res.setdefault(item["invoice_number"],[]).append(item)
+
+ out = get_cdnr_unreg_json(res, gstin)
+ gst_json["cdnur"] = out
+
+ elif filters["type_of_business"] == "Advances":
+ for item in report_data[:-1]:
+ if not item.get("place_of_supply"):
+ frappe.throw(_("""{0} not entered in some entries.
+ Please update and try again""").format(frappe.bold("Place Of Supply")))
+
+ res.setdefault(item["place_of_supply"],[]).append(item)
+
+ out = get_advances_json(res, gstin)
+ gst_json["at"] = out
return {
'report_name': report_name,
@@ -701,6 +854,40 @@ def get_b2cs_json(data, gstin):
return out
+def get_advances_json(data, gstin):
+ company_state_number = gstin[0:2]
+ out = []
+ for place_of_supply, items in iteritems(data):
+ supply_type = "INTRA" if company_state_number == place_of_supply.split('-')[0] else "INTER"
+ row = {
+ "pos": place_of_supply.split('-')[0],
+ "itms": [],
+ "sply_ty": supply_type
+ }
+
+ for item in items:
+ itms = {
+ 'rt': item['rate'],
+ 'ad_amount': flt(item.get('taxable_value')),
+ 'csamt': flt(item.get('cess_amount'))
+ }
+
+ if supply_type == "INTRA":
+ itms.update({
+ "samt": flt((itms["ad_amount"] * itms["rt"]) / 100),
+ "camt": flt((itms["ad_amount"] * itms["rt"]) / 100),
+ "rt": itms["rt"] * 2
+ })
+ else:
+ itms.update({
+ "iamt": flt((itms["ad_amount"] * itms["rt"]) / 100)
+ })
+
+ row['itms'].append(itms)
+ out.append(row)
+
+ return out
+
def get_b2cl_json(res, gstin):
out = []
for pos in res:
@@ -780,6 +967,27 @@ def get_cdnr_reg_json(res, gstin):
return out
+def get_cdnr_unreg_json(res, gstin):
+ out = []
+
+ for invoice, items in iteritems(res):
+ inv_item = {
+ "nt_num": items[0]["invoice_number"],
+ "nt_dt": getdate(items[0]["posting_date"]).strftime('%d-%m-%Y'),
+ "val": abs(flt(items[0]["invoice_value"])),
+ "ntty": items[0]["document_type"],
+ "pos": "%02d" % int(items[0]["place_of_supply"].split('-')[0]),
+ "typ": get_invoice_type_for_cdnrur(items[0])
+ }
+
+ inv_item["itms"] = []
+ for item in items:
+ inv_item["itms"].append(get_rate_and_tax_details(item, gstin))
+
+ out.append(inv_item)
+
+ return out
+
def get_invoice_type_for_cdnr(row):
if row.get('gst_category') == 'SEZ':
if row.get('export_type') == 'WPAY':
@@ -787,12 +995,23 @@ def get_invoice_type_for_cdnr(row):
else:
invoice_type = 'SEWOP'
elif row.get('gst_category') == 'Deemed Export':
- row.invoice_type = 'DE'
+ invoice_type = 'DE'
elif row.get('gst_category') == 'Registered Regular':
invoice_type = 'R'
return invoice_type
+def get_invoice_type_for_cdnrur(row):
+ if row.get('gst_category') == 'Overseas':
+ if row.get('export_type') == 'WPAY':
+ invoice_type = 'EXPWP'
+ else:
+ invoice_type = 'EXPWOP'
+ elif row.get('gst_category') == 'Unregistered':
+ invoice_type = 'B2CL'
+
+ return invoice_type
+
def get_basic_invoice_detail(row):
return {
"inum": row["invoice_number"],
@@ -832,7 +1051,7 @@ def get_company_gstin_number(company, address=None, all_gstins=False):
["Dynamic Link", "link_name", "=", company],
["Dynamic Link", "parenttype", "=", "Address"],
]
- gstin = frappe.get_all("Address", filters=filters, pluck="gstin")
+ gstin = frappe.get_all("Address", filters=filters, pluck="gstin", order_by="is_primary_address desc")
if gstin and not all_gstins:
gstin = gstin[0]
diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py
index 616c2b853df..5e44955ce30 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.py
+++ b/erpnext/regional/report/gstr_2/gstr_2.py
@@ -2,10 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from datetime import date
+
+import frappe
+
from erpnext.regional.report.gstr_1.gstr_1 import Gstr1Report
+
def execute(filters=None):
return Gstr2Report(filters).run()
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
index 1adddbdae57..7a938c7e0f2 100644
--- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
@@ -2,16 +2,20 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
-from frappe import _
-from frappe.utils import flt, getdate, cstr
-from frappe.model.meta import get_field_precision
-from frappe.utils.xlsxutils import handle_html
-from six import iteritems
+
import json
+
+import frappe
+from frappe import _
+from frappe.model.meta import get_field_precision
+from frappe.utils import cstr, flt, getdate
+from six import iteritems
+
+import erpnext
from erpnext.regional.india.utils import get_gst_accounts
from erpnext.regional.report.gstr_1.gstr_1 import get_company_gstin_number
+
def execute(filters=None):
return _execute(filters)
diff --git a/erpnext/regional/report/irs_1099/irs_1099.py b/erpnext/regional/report/irs_1099/irs_1099.py
index f67d622fdf8..b1a5d109621 100644
--- a/erpnext/regional/report/irs_1099/irs_1099.py
+++ b/erpnext/regional/report/irs_1099/irs_1099.py
@@ -3,16 +3,16 @@
import json
-from PyPDF2 import PdfFileWriter
-
import frappe
-from erpnext.accounts.utils import get_fiscal_year
from frappe import _
from frappe.utils import cstr, nowdate
from frappe.utils.data import fmt_money
from frappe.utils.jinja import render_template
from frappe.utils.pdf import get_pdf
from frappe.utils.print_format import read_multi_pdf
+from PyPDF2 import PdfFileWriter
+
+from erpnext.accounts.utils import get_fiscal_year
IRS_1099_FORMS_FILE_EXTENSION = ".pdf"
diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
index 54808e59e1a..5300b928925 100644
--- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
+++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py
@@ -2,9 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import get_conditions
+
+from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import (
+ get_conditions,
+)
+
def execute(filters=None):
data = get_data(filters)
diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
index 82423f005cc..ae5d6b90b4e 100644
--- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
+++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import getdate
from frappe import _
+from frappe.utils import getdate
+
def execute(filters=None):
data = get_data(filters)
diff --git a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
index daa69768c57..e19aeaa0eff 100644
--- a/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/test_uae_vat_201.py
@@ -1,21 +1,23 @@
# coding=utf-8
from __future__ import unicode_literals
-import erpnext
-import frappe
from unittest import TestCase
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+import frappe
+
+import erpnext
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.regional.report.uae_vat_201.uae_vat_201 import (
- get_total_emiratewise,
- get_tourist_tax_return_total,
- get_tourist_tax_return_tax,
- get_zero_rated_total,
get_exempt_total,
- get_standard_rated_expenses_total,
get_standard_rated_expenses_tax,
+ get_standard_rated_expenses_total,
+ get_total_emiratewise,
+ get_tourist_tax_return_tax,
+ get_tourist_tax_return_total,
+ get_zero_rated_total,
)
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse_account
test_dependencies = ["Territory", "Customer Group", "Supplier Group", "Item"]
diff --git a/erpnext/regional/report/uae_vat_201/uae_vat_201.py b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
index b0614238ba0..f4c049d1623 100644
--- a/erpnext/regional/report/uae_vat_201/uae_vat_201.py
+++ b/erpnext/regional/report/uae_vat_201/uae_vat_201.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
def execute(filters=None):
columns = get_columns()
data, emirates, amounts_by_emirate = get_data(filters)
diff --git a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
index dea17a66fda..77beff36ecd 100644
--- a/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/test_vat_audit_report.py
@@ -2,16 +2,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from unittest import TestCase
+
+import frappe
from frappe.utils import today
from erpnext.accounts.doctype.account.test_account import create_account
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
-
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.regional.report.vat_audit_report.vat_audit_report import execute
+
class TestVATAuditReport(TestCase):
def setUp(self):
frappe.set_user("Administrator")
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
index ebf297113d7..4514bb79de5 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
@@ -2,8 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
from frappe import _
from frappe.utils import formatdate, get_link_to_form
@@ -190,7 +192,7 @@ class VATAuditReport(object):
row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy")
row["voucher_type"] = doctype
row["voucher_no"] = inv
- row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
+ row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier"
row["party"] = inv_data.get("party")
row["remarks"] = inv_data.get("remarks")
row["gross_amount"]= item_details[0].get("gross_amount")
diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py
index 9b3677d2c64..3ccaae9e6a5 100644
--- a/erpnext/regional/saudi_arabia/setup.py
+++ b/erpnext/regional/saudi_arabia/setup.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
-from erpnext.regional.united_arab_emirates.setup import make_custom_fields, add_print_formats
+from erpnext.regional.united_arab_emirates.setup import add_print_formats, make_custom_fields
def setup(company=None, patch=True):
diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py
index 4657ff833dd..b13599ed0cb 100644
--- a/erpnext/regional/south_africa/setup.py
+++ b/erpnext/regional/south_africa/setup.py
@@ -7,6 +7,7 @@ import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
+
def setup(company=None, patch=True):
make_custom_fields()
add_permissions()
@@ -24,7 +25,7 @@ def make_custom_fields(update=True):
'Sales Invoice Item': is_zero_rated,
'Purchase Invoice Item': is_zero_rated
}
-
+
create_custom_fields(custom_fields, update=update)
def add_permissions():
@@ -36,7 +37,7 @@ def add_permissions():
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, 'write', 1)
update_permission_property(doctype, role, 0, 'create', 1)
-
+
if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")):
frappe.get_doc(dict(
diff --git a/erpnext/regional/turkey/setup.py b/erpnext/regional/turkey/setup.py
index 2396aab91f5..85d29b5da7f 100644
--- a/erpnext/regional/turkey/setup.py
+++ b/erpnext/regional/turkey/setup.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
def setup(company=None, patch=True):
pass
diff --git a/erpnext/regional/united_arab_emirates/setup.py b/erpnext/regional/united_arab_emirates/setup.py
index bd12d661f00..68da887bb72 100644
--- a/erpnext/regional/united_arab_emirates/setup.py
+++ b/erpnext/regional/united_arab_emirates/setup.py
@@ -3,11 +3,13 @@
from __future__ import unicode_literals
-import frappe, os, json
+import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.permissions import add_permission, update_permission_property
+
from erpnext.payroll.doctype.gratuity_rule.gratuity_rule import get_gratuity_rule
+
def setup(company=None, patch=True):
make_custom_fields()
add_print_formats()
diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py
index 7d5fd6ecf86..66a96514fc1 100644
--- a/erpnext/regional/united_arab_emirates/utils.py
+++ b/erpnext/regional/united_arab_emirates/utils.py
@@ -1,11 +1,14 @@
from __future__ import unicode_literals
+
import frappe
from frappe import _
-import erpnext
-from frappe.utils import flt, round_based_on_smallest_currency_fraction, money_in_words
-from erpnext.controllers.taxes_and_totals import get_itemised_tax
+from frappe.utils import flt, money_in_words, round_based_on_smallest_currency_fraction
from six import iteritems
+import erpnext
+from erpnext.controllers.taxes_and_totals import get_itemised_tax
+
+
def update_itemised_tax_data(doc):
if not doc.taxes: return
diff --git a/erpnext/regional/united_states/product_tax_category_data.json b/erpnext/regional/united_states/product_tax_category_data.json
new file mode 100644
index 00000000000..4527bb25384
--- /dev/null
+++ b/erpnext/regional/united_states/product_tax_category_data.json
@@ -0,0 +1,4084 @@
+{
+ "categories": [
+ {
+ "description": "An item commonly used by a student in a course of study. This category is limited to the following items...binders, blackboard chalk, cellophane tape, compasses, composition books, crayons, erasers, folders, glue/paste/glue sticks, highlighters, index cards, index card boxes, legal pads, lunch boxes, markers, notebooks, paper (copy, graph, tracing, manila, colored, construction, notebook), pencils, pencil boxes, pencil sharpeners, pens, posterboard, protractors, rulers, scissors, writing tablets.",
+ "name": "School Supplies",
+ "product_tax_code": "44121600A0001"
+ },
+ {
+ "description": "This is a labor charge for: the planning and design of interior spaces; preparation of layout drawings, schedules, and specifications pertaining to the planning and design of interior spaces; furniture arranging; design and planning of furniture, fixtures, and cabinetry; staging; lighting and sound design; and the selection, purchase, and arrangement of surface coverings, draperies, furniture, and other decorations.",
+ "name": "Interior Decorating Services",
+ "product_tax_code": "73890600A0000"
+ },
+ {
+ "description": "Ammunition for firearms with a barrel greater than an internal diameter of .50 caliber or a shotgun larger than 10 gauge., including bullets, shotgun shells, and gunpowder.",
+ "name": "Ammunition - designed for firearms other than small arms.",
+ "product_tax_code": "46101600A0002"
+ },
+ {
+ "description": "Firearms, limited to pistols, revolvers, rifles with a barrel greater than an internal diameter of .50 caliber or a shotgun larger than 10 gauge.",
+ "name": "Firearms - other than small arms",
+ "product_tax_code": "46101500A0002"
+ },
+ {
+ "description": "A charge for an objective visual examination of a house’s systems and physical structure. The charge includes a report of the inspector's findings including pictures, analysis, and recommendations.",
+ "name": "Home Inspection Services",
+ "product_tax_code": "80131802A0001"
+ },
+ {
+ "description": "A charge for custodial services to residential structures, including the cleaning of floors, carpets, walls, windows, appliances, furniture, fixtures, exterior cleaning, etc. No Tangible Personal Property is transferred.",
+ "name": "Cleaning/Janitorial Services - Residential",
+ "product_tax_code": "76111501A0001"
+ },
+ {
+ "description": "A subscription service for membership to an online dating platform.",
+ "name": "Online Dating Services",
+ "product_tax_code": "91000000A1111"
+ },
+ {
+ "description": "A charge for the service to maintain the proper operation of home or building gutters through cleaning out debris that could otherwise affect the proper water flow through the gutter system.",
+ "name": "Gutter Cleaning Services",
+ "product_tax_code": "72152602A0001"
+ },
+ {
+ "description": "Clothing - Swim Fins",
+ "name": "Clothing - Swim Fins",
+ "product_tax_code": "4914606A0001"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods can be streamed and/or downloaded to a device with permanent access granted. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded with permanent rights and streamed - non subscription",
+ "product_tax_code": "55111516A0110"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods can be streamed and/or downloaded to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded with limited rights and streamed - non subscription",
+ "product_tax_code": "55111516A0210"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are downloaded to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111516A0020"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are downloaded to a device with permanent access granted. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111516A0010"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed to a device with access that expires after a stated period of time. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - streamed - non subscription - with limited rights",
+ "product_tax_code": "55111516A0030"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed to a device with access that is conditioned upon continued subscription payment. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - streamed - subscription - with conditional rights",
+ "product_tax_code": "55111516A0040"
+ },
+ {
+ "description": "A series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any. These goods are streamed and/or downloaded to a device with access that is conditioned upon continued subscription payment. These goods include motion pictures, music videos, animations, news and entertainment programs, and live events, but do not include video greeting cards or video or electronic games.",
+ "name": "Digital Audio Visual Works - bundle - downloaded and streamed - subscription - with conditional rights",
+ "product_tax_code": "55111516A0310"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are streamed to a device with access that is conditioned upon continued subscription payment. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - streamed - subscription - with conditional rights",
+ "product_tax_code": "55111512A0040"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are streamed to a device with access that expires after a stated period of time. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - streamed - non subscription - with limited rights",
+ "product_tax_code": "55111512A0030"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111512A0010"
+ },
+ {
+ "description": "Works that result from the fixation of a series of musical, spoken, or other sounds that are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include prerecorded or live music, prerecorded or live readings of books or other written materials, prerecorded or live speeches, ringtones, or other sound recordings, but not including audio greeting cards.",
+ "name": "Digital Audio Works - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111512A0020"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Newspapers - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111507A0060"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "55111507A0040"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - viewable only - non subscription - with limited rights",
+ "product_tax_code": "55111507A0030"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals. The publication is accessed via a subscription which also entitles the purchaser to physical copies of the media.",
+ "name": "Digital Newspapers - subscription tangible and digital",
+ "product_tax_code": "55111507A0070"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Newspapers - downloadable - subscription - with conditional rights",
+ "product_tax_code": "55111507A0050"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "55111507A0010"
+ },
+ {
+ "description": "A digital version of a traditional newspaper published at regular intervals with the entire publication or individual articles downloaded to a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Newspapers - downloadable - non subscription - with limited rights",
+ "product_tax_code": "55111507A0020"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Magazines/Periodicals - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111506A0060"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "55111506A0040"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles viewable (but not downloadable) on a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - viewable only - non subscription - with limited rights",
+ "product_tax_code": "55111506A0030"
+ },
+ {
+ "description": "A digital version of a traditional magazine published at regular intervals. The publication is accessed via a subscription which also entitles the purchaser to physical copies of the media.",
+ "name": "Digital Magazines/Periodicals - subscription tangible and digital",
+ "product_tax_code": "55111506A0070"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital Magazines/Periodicals - downloadable - subscription - with conditional rights",
+ "product_tax_code": "55111506A0050"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with permanent access granted. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "55111506A0010"
+ },
+ {
+ "description": "A digital version of a traditional periodical published at regular intervals with the entire publication or individual articles downloaded to a device with access that expires after a stated period of time. The publication is accessed without a subscription.",
+ "name": "Digital Magazines/Periodicals - downloadable - non subscription - with limited rights",
+ "product_tax_code": "55111506A0020"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - viewable only - subscription - with conditional rights",
+ "product_tax_code": "55111505A0060"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - subscription - with conditional rights",
+ "product_tax_code": "55111505A0050"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111505A0010"
+ },
+ {
+ "description": "Works that are generally recognized in the ordinary and usual sense as books and are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include novels, autobiographies, encyclopedias, dictionaries, repair manuals, phone directories, business directories, zip code directories, cookbooks, etc.",
+ "name": "Digital Books - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111505A0020"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - subscription - with conditional rights",
+ "product_tax_code": "82141502A0050"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with permanent access granted. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "82141502A0010"
+ },
+ {
+ "description": "The final art used for actual reproduction by photomechanical or other processes or for display purposes, but does not include website or home page design, and that is transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time. These goods include drawings, paintings, designs, photographs, lettering, paste-ups, mechanicals, assemblies, charts, graphs, illustrative materials, etc.",
+ "name": "Digital Finished Artwork - downloaded - non subscription - with limited rights",
+ "product_tax_code": "82141502A0020"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital other news or documents - viewable only - subscription - with conditional rights",
+ "product_tax_code": "82111900A0002"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with permanent access granted.",
+ "name": "Digital other news or documents - viewable only - non subscription - with permanent rights",
+ "product_tax_code": "82111900A0005"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are viewable (but not downloadable) on a device with access that expires after a stated period of time.",
+ "name": "Digital other news or documents - viewable only - non subscription - with limited rights",
+ "product_tax_code": "82111900A0006"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Digital other news or documents - downloadable - subscription - with conditional rights",
+ "product_tax_code": "82111900A0001"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with permanent access granted. These publications are accessed without a subscription.",
+ "name": "Digital other news or documents - downloadable - non subscription - with permanent rights",
+ "product_tax_code": "82111900A0003"
+ },
+ {
+ "description": "Individual digital news articles, newsletters, and other stand-alone documents. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Digital other news or documents - downloadable - non subscription - with limited rights",
+ "product_tax_code": "82111900A0004"
+ },
+ {
+ "description": "Works that are required as part of a formal academic education program and are transferred electronically. These goods are downloaded to a device with permanent access granted.",
+ "name": "Digital School Textbooks - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "55111513A0010"
+ },
+ {
+ "description": "Works that are required as part of a formal academic education program and are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Digital School Textbooks - downloaded - non subscription - with limited rights",
+ "product_tax_code": "55111513A0020"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains only static images or text, rather than an audio visual or audio only experience.",
+ "name": "Digital Greeting Cards - Static text and/or images only",
+ "product_tax_code": "14111605A0003"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains a series of related images which, when shown in succession, impart an impression of motion, together with accompanying sounds, if any.",
+ "name": "Digital Greeting Cards - Audio Visual",
+ "product_tax_code": "14111605A0001"
+ },
+ {
+ "description": "An electronic greeting \"card\" typically sent via email that contains an audio only message.",
+ "name": "Digital Greeting Cards - Audio Only",
+ "product_tax_code": "14111605A0002"
+ },
+ {
+ "description": "Digital images that are downloaded to a device with permanent access granted.",
+ "name": "Digital Photographs/Images - downloaded - non subscription - with permanent rights for permanent use",
+ "product_tax_code": "60121011A0001"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are streamed to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Video Games - streamed - subscription - with conditional rights",
+ "product_tax_code": "60141104A0040"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are streamed to a device with access that expires after a stated period of time.",
+ "name": "Video Games - streamed - non subscription - with limited rights",
+ "product_tax_code": "60141104A0030"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with access that is conditioned upon continued subscription payment.",
+ "name": "Video Games - downloaded - subscription - with conditional rights",
+ "product_tax_code": "60141104A0050"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with permanent access granted.",
+ "name": "Video Games - downloaded - non subscription - with permanent rights",
+ "product_tax_code": "60141104A0010"
+ },
+ {
+ "description": "Video or electronic games in the common sense are transferred electronically. These goods are downloaded to a device with access that expires after a stated period of time.",
+ "name": "Video Games - downloaded - non subscription - with limited rights",
+ "product_tax_code": "60141104A0020"
+ },
+ {
+ "description": "The conceptualize, design, program or maintain a website. The code is unique to a particular client's website.",
+ "name": "Web Site Design",
+ "product_tax_code": "81112103A0000"
+ },
+ {
+ "description": "The process of renting or buying space to house a website on the World Wide Web. Website content such as HTML, CSS, and images has to be housed on a server to be viewable online.",
+ "name": "Web Hosting Services",
+ "product_tax_code": "81112105A0000"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself that entitles the purchaser to future repair and labor services to return the defective item of tangible personal property to its original state. The warranty contract is optional to the purchaser. Motor vehicle warranties are excluded.",
+ "name": "Warranty - Optional",
+ "product_tax_code": "81111818A0000"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself that entitles the purchaser to future repair and labor services to return the defective item of tangible personal property to its original state. The warranty contract is mandatory and is required to be purchased on conjunction with the purchased tangible personal property. Motor vehicle warranties are excluded.",
+ "name": "Warranty - Mandatory",
+ "product_tax_code": "81111818A0001"
+ },
+ {
+ "description": "Personal or small group teaching, designed to help people who need extra help with their studies",
+ "name": "Tutoring",
+ "product_tax_code": "86132001A0000"
+ },
+ {
+ "description": "Self Study web based training, not instructor led. This does not include downloads of video replays.",
+ "name": "Training Services - Self Study Web Based",
+ "product_tax_code": "86132000A0002"
+ },
+ {
+ "description": "Live training web based. This does not include video replays of the instruction or course.",
+ "name": "Training Services - Live Virtual",
+ "product_tax_code": "86132201A0000"
+ },
+ {
+ "description": "Charges for installing, configuring, debugging, modifying, testing, or troubleshooting computer hardware, networks, programs or software. Labor only charge.",
+ "name": "Technical Support Services",
+ "product_tax_code": "81111811A0001"
+ },
+ {
+ "description": "A charge to preserve an animal's body via mounting or stuffing, for the purpose of display or study. The customer provide the animal. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Taxidermy Services",
+ "product_tax_code": "82151508A0000"
+ },
+ {
+ "description": "A charge to have files or documents shredded either onsite or offsite.",
+ "name": "Shredding Service",
+ "product_tax_code": "44101603A9007"
+ },
+ {
+ "description": "A charge to repair or restore footwear was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential. Note: This product tax code will partially apply tax in CA, MI, IL.",
+ "name": "Shoe Repair",
+ "product_tax_code": "53111600A9007"
+ },
+ {
+ "description": "A charge for the printing, imprinting, lithographing, mimeographing, photocopying, and similar reproductions of various articles including mailers, catalogs, letterhead, envelopes, business cards, presentation folders, forms, signage, etc. The end result is the transfer of tangible personal property to the customer.",
+ "name": "Printing",
+ "product_tax_code": "82121500A0000"
+ },
+ {
+ "description": "Service processing payroll checks and tracking payroll data; including printing employees’ payroll checks, pay statements, management reports, tracking payroll taxes, preparing tax returns and producing W-2’s for distribution.",
+ "name": "Payroll Services",
+ "product_tax_code": "87210202A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition a motor vehicle that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Motor Vehicle Repair",
+ "product_tax_code": "25100000A9007"
+ },
+ {
+ "description": "A charge to make customer provided meat suitable for human consumption, typically referred to a butcher or slaughter services.",
+ "name": "Meat Processing",
+ "product_tax_code": "42447000A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition a machine that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Machine Repair",
+ "product_tax_code": "23019007A0000"
+ },
+ {
+ "description": "A charge to provide laundry services to linens and the like. This charge is not for clothing items. The business customer is the owner of the items being cleaned.",
+ "name": "Linen Services - Laundry only - items other than clothing",
+ "product_tax_code": "91111502A1601"
+ },
+ {
+ "description": "A charge to provide laundry services to clothing. The business customer is the owner of the items being cleaned.",
+ "name": "Linen Services - Laundry only",
+ "product_tax_code": "91111502A1600"
+ },
+ {
+ "description": "A charge to repair or restore jewelry that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Jewelry Repair",
+ "product_tax_code": "54119007A0000"
+ },
+ {
+ "description": "A charge for the wrapping of articles in a box or bag with paper and other decorative additions. The wrapping not linked the purchased of the article(s) and is performed by a party other vendor of the article(s).",
+ "name": "Gift Wrapping - separate from purchase of article",
+ "product_tax_code": "14111601A9007"
+ },
+ {
+ "description": "A charge for the wrapping of articles in a box or bag with paper and other decorative additions. The charge is separately stated from the article.",
+ "name": "Gift Wrapping - in conjunction with purchase of article",
+ "product_tax_code": "14111601A0001"
+ },
+ {
+ "description": "A charge to perform an alteration on a item of clothing by a service provider other than vendor of the article. The alteration is not linked to the clothing purchase. Alterations could include hemming of a dress, shortening of pants, adjusting the waistline of a garment, etc.",
+ "name": "Garment Alterations- separate from purchase of garment",
+ "product_tax_code": "81149000A0000"
+ },
+ {
+ "description": "A charge to perform an alteration on a item of clothing by the vendor of the article. The alteration is separately stated from the clothing, but contracted for at the time of the clothing purchase. Alterations could include hemming of a dress, shortening of pants, adjusting the waistline of a garment, etc.",
+ "name": "Garment Alterations- in conjunction with purchase of garment",
+ "product_tax_code": "81149000A0001"
+ },
+ {
+ "description": "A separately stated labor charge to cover a piece of furniture previously owned by the customer with new fabric coverings. Any materials transferred as part of the service are separately stated.",
+ "name": "Furniture Reupholstering",
+ "product_tax_code": "72153614A0000"
+ },
+ {
+ "description": "A charge to create a finished good from materials supplied by the customer. This is a labor only charge to transform a customer's existing property.",
+ "name": "Fabrication",
+ "product_tax_code": "23839000A0000"
+ },
+ {
+ "description": "E-file services for tax returns",
+ "name": "Electronic Filing Service",
+ "product_tax_code": "72910000A0000"
+ },
+ {
+ "description": "Private schools, not college or university",
+ "name": "Educational Services",
+ "product_tax_code": "86132209A0000"
+ },
+ {
+ "description": "A charge to a non-commercial customer for the cleaning or renovating items other than clothing by immersion and agitation, spraying, vaporization, or immersion only, in a volatile, commercially moisture-free solvent or by the use of a volatile or inflammable product. This does not include the use of a self-service coin (or credit card) operated cleaning machine.",
+ "name": "Dry Cleaning - items other than clothing",
+ "product_tax_code": "91111503A1601"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition computer hardware that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Computer Repair",
+ "product_tax_code": "81112300A0000"
+ },
+ {
+ "description": "A charge to clean, wash or wax a motor vehicle, other than a self-service coin (or credit card) operated washing station. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Car Washing",
+ "product_tax_code": "81119200A0000"
+ },
+ {
+ "description": "A charge to assemble goods for a purchaser who will later sell the assembled goods to end consumers.",
+ "name": "Assembly - prior to final purchase of article",
+ "product_tax_code": "93121706A0001"
+ },
+ {
+ "description": "A charge separately stated from the sale of the product itself to bring the article to its finished state and in the condition specified by the buyer.",
+ "name": "Assembly - in conjunction with final purchase of article",
+ "product_tax_code": "93121706A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition an appliance (dishwasher, washing machine, refrigerator, etc.) that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Appliance Repair",
+ "product_tax_code": "52143609A0000"
+ },
+ {
+ "description": "A charge to repair or restore to operating condition an aircraft that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential. Commercial aircraft is excluded.",
+ "name": "Aircraft Repair",
+ "product_tax_code": "78181800A0000"
+ },
+ {
+ "description": "A charge for the printing, imprinting, or lithographing on any article supplied by the customer. The customer owns the article throughout the process. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Printing - customer supplied articles",
+ "product_tax_code": "19009"
+ },
+ {
+ "description": "A charge to a non-commercial customer for the cleaning or renovating clothing by immersion and agitation, spraying, vaporization, or immersion only, in a volatile, commercially moisture-free solvent or by the use of a volatile or inflammable product. This does not include the use of a self-service coin (or credit card) operated cleaning machine.",
+ "name": "Dry Cleaning Services",
+ "product_tax_code": "19006"
+ },
+ {
+ "description": "A charge to repair or restore tangible personal property that was broken, worn, damaged, defective, or malfunctioning. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Repair Services",
+ "product_tax_code": "19007"
+ },
+ {
+ "description": "Food for household pets that is consumed for nutritional value. This code is not intended for food related to working farm animals or animals raised for meat or milk production. This code is intended for retail sales made directly to end consumers.",
+ "name": "OTC Pet Food",
+ "product_tax_code": "10122100A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising between 25% and 49% of the overall value of the bundle (food comprises 51 to 75%). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 25% to 49%",
+ "product_tax_code": "50193400A0008"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising between 11% and 24% of the overall value of the bundle (food comprises 76% to 89%). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 11% to 24%",
+ "product_tax_code": "50193400A0009"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising 10% or less of the overall value of the bundle (food comprises 90% or more). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 10% or less",
+ "product_tax_code": "50193400A0010"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with candy, with the candy comprising 50% or more of the overall value of the bundle (food comprises 50% or less). Note that any candy containing flour should be considered as food (and not candy) when determining bundle percentages.",
+ "name": "Food/Candy Bundle - with Candy 50% or more",
+ "product_tax_code": "50193400A0007"
+ },
+ {
+ "description": "Male or female condoms and vaginal sponges used to prevent pregnancy and/or exposure to STDs, containing a spermicidal lubricant as indicated by a \"drug facts\" panel or a statement of active ingredients, sold under prescription order of a licensed professional.",
+ "name": "Condoms with Spermicide with Prescription",
+ "product_tax_code": "53131622A0004"
+ },
+ {
+ "description": "Over-the-Counter emergency contraceptive pills act to prevent pregnancy after intercourse. The contraceptive contains a hormone that prevents ovulation, fertilization, or implantation of an embryo.",
+ "name": "Birth Control - Over-the-Counter Oral Contraceptives",
+ "product_tax_code": "51350000A0001"
+ },
+ {
+ "description": "An oral medication containing hormones effective in altering the menstrual cycle to eliminate ovulation and prevent pregnancy, available only under prescription order of a licensed professional. Other than preventing pregnancy, hormonal birth control can also be used to treat various conditions, such as Polycystic Ovary Syndrome, Endometriosis, Primary Ovarian Insufficiency, etc.",
+ "name": "Birth Control - Prescription Oral Contraceptives",
+ "product_tax_code": "51350000A0000"
+ },
+ {
+ "description": "Over-the-Counter emergency contraceptive pills act to prevent pregnancy after intercourse, sold under prescription order of a licensed professional. The contraceptive contains a hormone that prevents ovulation, fertilization, or implantation of an embryo.",
+ "name": "Birth Control - Over-the-Counter Oral Contraceptives with Prescription",
+ "product_tax_code": "51350000A0002"
+ },
+ {
+ "description": "Barrier based prescription only birth control methods, including the diaphragm and cervical cap that prevent the joining of the sperm and egg, available only under prescription order of a licensed professional.",
+ "name": "Birth Control - Prescription non-Oral Contraceptives - Barriers",
+ "product_tax_code": "42143103A0000"
+ },
+ {
+ "description": "Hormonal based birth control methods other than the oral pill, including intrauterine devices, injections, skin implants, transdermal patches, and vaginal rings that release a continuous dose of hormones to eliminate ovulation and prevent pregnancy, available only under prescription order of a licensed professional.",
+ "name": "Birth Control - Prescription non-Oral Contraceptives - Hormonal",
+ "product_tax_code": "51350000A0003"
+ },
+ {
+ "description": "Male or female condoms and vaginal sponges used to prevent pregnancy and/or exposure to STDs, sold under prescription order of a licensed professional.",
+ "name": "Condoms with Prescription",
+ "product_tax_code": "53131622A0003"
+ },
+ {
+ "description": "Feminine hygiene product designed to absorb the menstrual flow. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Tampons, menstrual cups, pads, liners",
+ "product_tax_code": "53131615A0000"
+ },
+ {
+ "description": "Infant washable/reusable cloth diapers.",
+ "name": "Clothing - Cloth Diapers",
+ "product_tax_code": "53102305A0001"
+ },
+ {
+ "description": "Clothing - Diaper liners",
+ "name": "Clothing - Diaper liners",
+ "product_tax_code": "53102308A0000"
+ },
+ {
+ "description": "Clothing - Adult diapers",
+ "name": "Clothing - Adult diapers",
+ "product_tax_code": "53102306A0000"
+ },
+ {
+ "description": "Clothing - Infant diapers",
+ "name": "Clothing - Infant diapers",
+ "product_tax_code": "53102305A0000"
+ },
+ {
+ "description": "Food and Beverage - Candy containing flour as an ingredient",
+ "name": "Food and Beverage - Candy containing flour as an ingredient",
+ "product_tax_code": "50161800A0001"
+ },
+ {
+ "description": "Food and Beverage - Food and Food Ingredients for Home Consumption",
+ "name": "Food and Beverage - Food and Food Ingredients for Home Consumption",
+ "product_tax_code": "50000000A0000"
+ },
+ {
+ "description": "Clothing - Zippers",
+ "name": "Clothing - Zippers",
+ "product_tax_code": "53141503A0000"
+ },
+ {
+ "description": "Clothing - Gorgets",
+ "name": "Clothing - Gorgets",
+ "product_tax_code": "53102519A0000"
+ },
+ {
+ "description": "Clothing - Shoulder boards or epaulettes",
+ "name": "Clothing - Shoulder boards or epaulettes",
+ "product_tax_code": "53102520A0000"
+ },
+ {
+ "description": "Yarn - For use other than fabricating/repairing clothing",
+ "name": "Yarn - For use other than fabricating/repairing clothing",
+ "product_tax_code": "11151700A0001"
+ },
+ {
+ "description": "Clothing - Snaps",
+ "name": "Clothing - Snaps",
+ "product_tax_code": "53141506A0000"
+ },
+ {
+ "description": "Clothing - Clasps",
+ "name": "Clothing - Clasps",
+ "product_tax_code": "53141507A0000"
+ },
+ {
+ "description": "Clothing - Buttons",
+ "name": "Clothing - Buttons",
+ "product_tax_code": "53141505A0000"
+ },
+ {
+ "description": "Clothing - Clothing - Fabric dye",
+ "name": "Clothing - Fabric dye",
+ "product_tax_code": "60105810A0000"
+ },
+ {
+ "description": "Clothing - Fabric for use in clothing",
+ "name": "Clothing - Fabric for use in clothing",
+ "product_tax_code": "11160000A0000"
+ },
+ {
+ "description": "Clothing - Clothing - Yarn",
+ "name": "Clothing - Yarn",
+ "product_tax_code": "11151700A0000"
+ },
+ {
+ "description": "A lump sum charge where both the downloaded digital products and the service components each are greater than 10% of the bundle.",
+ "name": "Digital Products (> 10%) / General Services (> 10%) Bundle",
+ "product_tax_code": "55111500A5000"
+ },
+ {
+ "description": "Services provided by a licensed or registered professional in the medical field. Examples: Doctor, dentist, nurse, optometrist, etc.",
+ "name": "Medical Professional Services - Physician, Dentist, and similar",
+ "product_tax_code": "62139900A0000"
+ },
+ {
+ "description": "The puncturing or penetration of the skin of a person and the insertion of jewelry or other adornment into the opening.",
+ "name": "Body Piercing",
+ "product_tax_code": "72990190A0000"
+ },
+ {
+ "description": "Cosmetic beauty treatment for the fingernails and toenails. Consists of filing, cutting and shaping and the application of polish.",
+ "name": "Manicure Services",
+ "product_tax_code": "72310104A0000"
+ },
+ {
+ "description": "Performing tests and research for a particular client in connection with the development of particular products, property, goods or services that the client sells to consumers in the regular course of business.",
+ "name": "Marketing Services",
+ "product_tax_code": "87420300A0000"
+ },
+ {
+ "description": "Performing surveying and mapping services of the surface of the earth, including the sea floor. These services may include surveying and mapping of areas above or below the surface of the earth, such as the creation of view easements or segregating rights in parcels of land by creating underground utility easements.",
+ "name": "Property Surveying Services",
+ "product_tax_code": "87130000A0000"
+ },
+ {
+ "description": "Providing a systematic inquiry, examination, or analysis of people, events or documents, to determine the facts of a given situation. The evaluation is submitted in the form of a report or provided as a testimony in legal proceedings. Techniques such as surveillance, background checks, computer searches, fingerprinting, lie detector services, and interviews may be used to gather the information.",
+ "name": "Private Investigator Services",
+ "product_tax_code": "73810204A0000"
+ },
+ {
+ "description": "The provision of expertise or strategic advice that is presented for consideration and decision-making.",
+ "name": "Consulting Services",
+ "product_tax_code": "87480000A0000"
+ },
+ {
+ "description": "Services relating to advocating for the passage or defeat of legislation to members or staff of the government.",
+ "name": "Lobbying Services",
+ "product_tax_code": "87439901A0000"
+ },
+ {
+ "description": "Preparation of materials, written or otherwise, that are designed to influence the general public or other groups by promoting the interests of a service recipient.",
+ "name": "Public Relations",
+ "product_tax_code": "87430000A0000"
+ },
+ {
+ "description": "Services related to the art and science of designing and building structures for human habitation or use and includes planning, providing preliminary studies, designs, specifications, working drawings and providing for general administration of construction contracts.",
+ "name": "Architectural Services",
+ "product_tax_code": "87120000A0000"
+ },
+ {
+ "description": "Services provided by a profession trained to apply physical laws and principles of engineering in the design, development, and utilization of machines, materials, instruments, structures, processes, and systems. The services involve any of the following activities: provision of advice, preparation of feasibility studies, preparation of preliminary and final plans and designs, provision of technical services during the construction or installation phase, inspection and evaluation of engineering projects, and related services.",
+ "name": "Engineering Services",
+ "product_tax_code": "87110000A0000"
+ },
+ {
+ "description": "Services that provide non-medical care and supervision for infant to school-age children or senior citizens.",
+ "name": "Childcare Services / Adultcare",
+ "product_tax_code": "83510000A0000"
+ },
+ {
+ "description": "Services provided by a facility for overnight care of an animal not related to veterinary care.",
+ "name": "Pet Services - Boarding",
+ "product_tax_code": "81291000A0001"
+ },
+ {
+ "description": "Services relating to or concerned with the law. Such services include, but are not limited to, representation by an attorney (or other person, when permitted) in an administrative or legal proceeding, legal drafting, paralegal services, legal research services, arbitration, mediation, and court reporting services.",
+ "name": "Legal Services",
+ "product_tax_code": "81110000A0000"
+ },
+ {
+ "description": "Medical procedure performed on an individual that is directed at improving the individual's appearance and that does not meaningfully promote the proper function of the body or prevent or treat illness or disease.",
+ "name": "Cosmetic Medical Procedure",
+ "product_tax_code": "80110517A0000"
+ },
+ {
+ "description": "Alarm monitoring involves people using computers, software, and telecommunications to monitor homes and businesses for break-ins, fires, and other unexpected events.",
+ "name": "Security - Alarm Services",
+ "product_tax_code": "73829901A0000"
+ },
+ {
+ "description": "Services related to protecting persons or their property, preventing the theft of goods, merchandise, or money. Responding to alarm signal device, burglar alarm, television camera, still camera, or a mechanical or electronic device installed or used to prevent or detect burglary, theft, shoplifting, pilferage, losses, or other security measures. Providing management and control of crowds for safety and protection.",
+ "name": "Security - Guard Services",
+ "product_tax_code": "73810105A0000"
+ },
+ {
+ "description": "Transporting under armed private security guard from one place to another any currency, jewels, stocks, bonds, paintings, or other valuables of any kind in a specially equipped motor vehicle that offers a high degree of security.",
+ "name": "Armored Car Services",
+ "product_tax_code": "73810101A0000"
+ },
+ {
+ "description": "Services related to providing personnel, on a temporary basis, to perform work or labor under the supervision or control of another.",
+ "name": "Temporary Help Services",
+ "product_tax_code": "73630103A0000"
+ },
+ {
+ "description": "Services employment agencies provide are finding a job for a job-seeker and finding an employee for an employer.",
+ "name": "Employment Services",
+ "product_tax_code": "73610000A0000"
+ },
+ {
+ "description": "Services to industrial, commercial or income-producing real property, such as as management, electrical, plumbing, painting and carpentry, provided to income-producing property.",
+ "name": "Building Management Services",
+ "product_tax_code": "73490000A0000"
+ },
+ {
+ "description": "Services which include, but are not limited to, editing, letter writing, proofreading, resume writing, typing or word processing.  Not including court reporting and stenographic services.",
+ "name": "Secretarial Services",
+ "product_tax_code": "73389903A0000"
+ },
+ {
+ "description": "Services that include typing, taking shorthand, and taking and transcribing dictation for others for a consideration.",
+ "name": "Stenographic Services",
+ "product_tax_code": "73380200A0000"
+ },
+ {
+ "description": "A process that uses needles and colored ink to permanently put a mark or design on a person’s skin. Also applying permanent make-up, such as eyelining and other permanent colors to enhance the skin of the face, lips, eyelids, and eyebrows.",
+ "name": "Tattooing Services",
+ "product_tax_code": "72990106A0000"
+ },
+ {
+ "description": "A variety of personal services typically with the purpose of improving health, beauty and relaxation through treatments such as hair, massages and facials.",
+ "name": "Spa Services",
+ "product_tax_code": "72990201A0000"
+ },
+ {
+ "description": "Services where the use of structured touch, include holding, applying pressure, positioning, and mobilizing soft tissue of the body by manual technique. Note: This does not include medical massage prescribed by a physician.",
+ "name": "Massage Services",
+ "product_tax_code": "72990200A0000"
+ },
+ {
+ "description": "The measurement, processing and communication of financial information about economic entities including, but is not limited to, financial accounting, management accounting, auditing, cost containment and auditing services, taxation and accounting information systems; excluding general bookkeeping service.",
+ "name": "Accounting Services",
+ "product_tax_code": "87210200A0000"
+ },
+ {
+ "description": "The training of an animal to obey certain commands.",
+ "name": "Pet Services - Obedience Training",
+ "product_tax_code": "81291000A0002"
+ },
+ {
+ "description": "Credit monitoring services are companies consumers pay to keep an eye on your credit files. The services notifies one when they see activity in credit files, so one can determine if that activity is a result of action one took or possibly fraudulent",
+ "name": "Credit Monitoring Services",
+ "product_tax_code": "56145000A0000"
+ },
+ {
+ "description": "Grooming services for an animal such as haircuts, bathing, nail trimming, and flea dips.",
+ "name": "Pet Services - Grooming",
+ "product_tax_code": "81291000A0000"
+ },
+ {
+ "description": "Debt collection is when a collection agency or company tries to collect past-due debts from borrowers.",
+ "name": "Debt Collection Services",
+ "product_tax_code": "73229902A0000"
+ },
+ {
+ "description": "A service that arranges introductions, for a fee, for strangers seeking romantic partners or friends. This excludes online dating services.",
+ "name": "Dating Services",
+ "product_tax_code": "72990301A0000"
+ },
+ {
+ "description": "A service that allows merchants to accept credit cards as well as send credit card payment details to the credit card network. It then forwards the payment authorization back to the acquiring bank.",
+ "name": "Credit Card Processing Services",
+ "product_tax_code": "52232000A0000"
+ },
+ {
+ "description": "Services for artificial tanning and skin beautification.",
+ "name": "Tanning Services",
+ "product_tax_code": "72990105A0000"
+ },
+ {
+ "description": "Credit reporting agencies receive various types of information which can be included in their offerings for customers.",
+ "name": "Credit Reporting Services",
+ "product_tax_code": "73230000A0000"
+ },
+ {
+ "description": "Miscellaneous personal services are generally services that affect the appearance or comfort of people. This does not include haircutting/styling services",
+ "name": "Personal Services",
+ "product_tax_code": "72990000A0000"
+ },
+ {
+ "description": "The removal of hair from the face or body using chemicals or heat energy.",
+ "name": "Electrolysis",
+ "product_tax_code": "72310102A0000"
+ },
+ {
+ "description": "Services provided to insurance companies providing insurance to consumers. Examples are loss or damage appraisals, inspections, actuarial services, claims adjustment or processing. Investigations as excluded from this definition.",
+ "name": "Insurance Services",
+ "product_tax_code": "64110000A0000"
+ },
+ {
+ "description": "An at-home infectious disease test kit that can be sold without a prescription.",
+ "name": "Infectious Disease Test - Over-the-Counter",
+ "product_tax_code": "41116205A0005"
+ },
+ {
+ "description": "An at-home infectious disease test kit that can only be sold with a prescription.",
+ "name": "Infectious Disease Test - Prescription only",
+ "product_tax_code": "41116205A0004"
+ },
+ {
+ "description": "Online database information retrieval service (personal or individual)",
+ "name": "Online database information retrieval service (personal or individual)",
+ "product_tax_code": "81111902A0001"
+ },
+ {
+ "description": "Database information retrieval",
+ "name": "Database information retrieval (personal or individual)",
+ "product_tax_code": "81111901A0001"
+ },
+ {
+ "description": "Services provided by beauty shops and barber shops, including but not limited to haircutting, hair coloring, shampooing, blow drying, permanents, hair extensions, hair straightening, and hair restorations.",
+ "name": "Hairdressing Services",
+ "product_tax_code": "19008"
+ },
+ {
+ "description": "Professional services which are not subject to a service-specific tax levy.",
+ "name": "Professional Services",
+ "product_tax_code": "19005"
+ },
+ {
+ "description": "Online database information retrieval service",
+ "name": "Online database information retrieval service",
+ "product_tax_code": "81111902A0000"
+ },
+ {
+ "description": "Database information retrieval",
+ "name": "Database information retrieval",
+ "product_tax_code": "81111901A0000"
+ },
+ {
+ "description": "Cash donation",
+ "name": "Cash donation",
+ "product_tax_code": "14111803A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription billed to Medicaid",
+ "product_tax_code": "42271700A0008"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged,",
+ "name": "Kidney Dialysis Equipment for home use without Prescription",
+ "product_tax_code": "42161800A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42140000A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42161800A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42140000A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42271700A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription",
+ "product_tax_code": "42140000A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42271700A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42271700A0010"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription",
+ "product_tax_code": "42271700A0012"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, medical grade oyxgen.",
+ "name": "Medical Oxygen without Prescription",
+ "product_tax_code": "42271700A0011"
+ },
+ {
+ "description": "Equipment which is primarily and customarily used to provide or increase the ability to move from one place to another, sold without a prescription, and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment without Prescription",
+ "product_tax_code": "42211500A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42271700A0003"
+ },
+ {
+ "description": "Synthetic or animal-based insulin used as an injectible drug for diabetes patients, sold under prescription order of a licensed professional.",
+ "name": "Insulin with Prescription",
+ "product_tax_code": "51183603A0000"
+ },
+ {
+ "description": "Devices used by diabetic individuals to monitor sugar levels in the blood, sold under prescription order of a licensed professional.",
+ "name": "Blood Glucose Monitoring Devices with Prescription",
+ "product_tax_code": "41116201A0000"
+ },
+ {
+ "description": "Devices used by diabetic individuals to monitor sugar levels in the blood, sold without prescription order of a licensed professional.",
+ "name": "Blood Glucose Monitoring Devices without Prescription",
+ "product_tax_code": "41116201A0001"
+ },
+ {
+ "description": "At home urine-based tests used to detect the presense of various drug substances in an individual.",
+ "name": "Drug Testing Kits",
+ "product_tax_code": "41116136A0001"
+ },
+ {
+ "description": "Single use hollow needle commonly used with a syringe to inject insulin into the body by diabetic individuals, sold under prescription order of a licensed professional.",
+ "name": "Hypodermic Needles/Syringes with prescription - Insulin",
+ "product_tax_code": "42142523A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription reimbursed by Medicare",
+ "product_tax_code": "42271700A0009"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, medical grade oyxgen.",
+ "name": "Medical Oxygen with Prescription billed to Medicare",
+ "product_tax_code": "42271700A0007"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthopedics, ostomy/colostomy devices, etc.",
+ "name": "Prosthetic Devices without Prescription",
+ "product_tax_code": "42242000A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Billed to Medicaid",
+ "product_tax_code": "42242000A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Billed to Medicare",
+ "product_tax_code": "42242000A0002"
+ },
+ {
+ "description": "At home saliva, cheeek swab or blood drop based tests used to detect various genetic markers in an individual.",
+ "name": "DNA Testing Kits",
+ "product_tax_code": "41116205A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42231500A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription reimbursed by Medicaid",
+ "product_tax_code": "42271700A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use with Prescription",
+ "product_tax_code": "42271700A0001"
+ },
+ {
+ "description": "Synthetic or animal-based insulin used as an injectible drug for diabetes patients, sold without prescription order of a licensed professional.",
+ "name": "Insulin without Prescription",
+ "product_tax_code": "51183603A0001"
+ },
+ {
+ "description": "Single use hollow needle commonly used with a syringe to inject insulin into the body by diabetic individuals, sold without prescription order of a licensed professional.",
+ "name": "Hypodermic Needles/Syringes without prescription - Insulin",
+ "product_tax_code": "42142523A0001"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, equipment used to administer oxygen directly into the lungs of the patient for the relief of conditions in which the human body experiences an abnormal deficiency or inadequate supply of oxygen. Oxygen equipment means oxygen cylinders, cylinder transport devices, including sheaths and carts, cylinder studs and support devices, regulators, flowmeters, tank wrenches, oxygen concentrators, liquid oxygen base dispensers, liquid oxygen portable dispensers, oxygen tubing, nasal cannulas, face masks, oxygen humidifiers, and oxygen fittings and accessories.",
+ "name": "Oxygen Delivery Equipment for home use without Prescription",
+ "product_tax_code": "42271700A0006"
+ },
+ {
+ "description": "At home blood-prick based tests used to monitor cholesterol levels in an individual.",
+ "name": "Cholesterol Testing Kits",
+ "product_tax_code": "41116202A0001"
+ },
+ {
+ "description": "Single use supplies utilized by diabetics in the regular blood sugar monitoring regimen. Includes skin puncture lancets, test strips for blood glucose monitors, visual read test strips, and urine test strips, sold under prescription order of a licensed professional.",
+ "name": "Diabetic Testing Supplies - single use - with Prescription",
+ "product_tax_code": "41116120A0002"
+ },
+ {
+ "description": "A breast pump is a mechanical device that lactating women use to extract milk from their breasts. They may be manual devices powered by hand or foot movements or automatic devices powered by electricity.",
+ "name": "Breast Pumps",
+ "product_tax_code": "42231901A0000"
+ },
+ {
+ "description": "At home urine-based tests used to detect pregancy hormone levels.",
+ "name": "Pregenacy Testing Kits",
+ "product_tax_code": "41116205A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and reimbursed by Medicaid, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Reimbursed by Medicaid",
+ "product_tax_code": "42211500A0005"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, a replacement, corrective, or supportive device, worn in the mouth, including dentures, orthodontics, crowns, bridges, etc.",
+ "name": "Dental Prosthetics without Prescription",
+ "product_tax_code": "42151500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a replacement, corrective, or supportive device, worn in the mouth, including dentures, orthodontics, crowns, bridges, etc.",
+ "name": "Dental Prosthetics with Prescription",
+ "product_tax_code": "42151500A0001"
+ },
+ {
+ "description": "At home urine-based tests used to detect impending ovulation to assist in pregnancy planning.",
+ "name": "Ovulation Testing Kits",
+ "product_tax_code": "41116205A0002"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use without Prescription",
+ "product_tax_code": "42231500A0006"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42231500A0004"
+ },
+ {
+ "description": "When sold without prescription order of a licensed professional, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use without Prescription",
+ "product_tax_code": "42140000A0006"
+ },
+ {
+ "description": "Male or female condoms used to prevent pregnancy or exposure to STDs, containing a spermicidal lubricant as indicated by a \"drug facts\" panel or a statement of active ingredients.",
+ "name": "Condoms with Spermicide",
+ "product_tax_code": "53131622A0001"
+ },
+ {
+ "description": "Single use supplies utilized by diabetics in the regular blood sugar monitoring regimen. Includes skin puncture lancets, test strips for blood glucose monitors, visual read test strips, and urine test strips.",
+ "name": "Diabetic Testing Supplies - single use - without Prescription",
+ "product_tax_code": "41116120A0001"
+ },
+ {
+ "description": "An electronic device that clips onto a patient's finger to measure heart rate and oxygen saturation in his or her red blood cells.",
+ "name": "Pulse Oximeter",
+ "product_tax_code": "42181801A0000"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription",
+ "product_tax_code": "42211500A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription",
+ "product_tax_code": "42242000A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42231500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42140000A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Reimbursed by Medicare",
+ "product_tax_code": "42242000A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and billed to Medicare, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Billed to Medicare",
+ "product_tax_code": "42211500A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and billed to Medicaid, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Billed to Medicaid",
+ "product_tax_code": "42211500A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicare, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription reimbursed by Medicare",
+ "product_tax_code": "42161800A0004"
+ },
+ {
+ "description": "At home digital or manual (aneroid) sphygmomanometers, also known as a blood pressure meter, blood pressure monitor, or blood pressure gauge, are devices used to measure blood pressure, composed of an inflatable cuff to collapse and then release the artery under the cuff in a controlled manner.",
+ "name": "Blood Pressure Testing Devices",
+ "product_tax_code": "42181600A0001"
+ },
+ {
+ "description": "A topical preparation containing a spermicidal lubricant to prevent pregnancy as indicated by a \"drug facts\" panel or a statement of active ingredients.",
+ "name": "Contraceptive Ointments",
+ "product_tax_code": "53131622A0002"
+ },
+ {
+ "description": "Male or female condoms used to prevent pregnacy or exposure to STDs.",
+ "name": "Condoms",
+ "product_tax_code": "53131622A0000"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicare, equipment that: can withstand repeated use; is primarily and customarily used to serve a medical purpose; generally is not useful to a person in the absence of illness or injury; and is not worn in or on the body. Home use means the equipment is sold to an individual for use at home, regardless of where the individual resides. Examples include hospital beds, commode chairs, bed pans, shower and bath aids, IV poles, etc.",
+ "name": "Durable Medical Equipment for home use with Prescription billed to Medicare",
+ "product_tax_code": "42140000A0002"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, a replacement, corrective, or supportive device, worn on or in the body to: Artificially replace a missing portion of the body; Prevent or correct physical deformity or malfunction; or Support a weak or deformed portion of the body. Worn in or on the body means that the item is implanted or attached so that it becomes part of the body, or is carried by the body and does not hinder the mobility of the individual. Examples include artificial limbs, pacemakers, orthotics, orthopedics, ostomy/colostomy devices, catheters, etc.",
+ "name": "Prosthetic Devices with Prescription Reimbursed by Medicaid",
+ "product_tax_code": "42242000A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, and reimbursed by Medicare, equipment which is primarily and customarily used to provide or increase the ability to move from one place to another and which is appropriate for use either in a home or a motor vehicle; Is not generally used by persons with normal mobility; and Does not include any motor vehicle or equipment on a motor vehicle normally provided by a motor vehicle manufacturer. Examples include wheelchairs, crutches, canes, walkers, chair lifts, etc.",
+ "name": "Mobility Enhancing Equipment with Prescription Reimbursed by Medicare",
+ "product_tax_code": "42211500A0004"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with prescription billed to Medicaid",
+ "product_tax_code": "42231500A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, nutritional tube feeding equipment including button-style feeding tubes, standard G-tubes, NG-tubes, extension sets, adapters, feeding pumps, feeding pump delivery sets.",
+ "name": "Enteral Feeding Equipment for home use with Prescription",
+ "product_tax_code": "42231500A0001"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and billed directly to Medicaid, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription billed to Medicaid",
+ "product_tax_code": "42161800A0003"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional and reimbursed by Medicaid, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription and reimbursed by Medicaid",
+ "product_tax_code": "42161800A0005"
+ },
+ {
+ "description": "When sold under prescription order of a licensed professional, a machine used that filters a patient's blood to remove excess water and waste products when the kidneys are damaged, dysfunctional, or missing. The kidney dialysis machine is an artificial part which augments the natural functioning of the kidneys.",
+ "name": "Kidney Dialysis Equipment for home use with Prescription",
+ "product_tax_code": "42161800A0001"
+ },
+ {
+ "description": "Handbags, Purses",
+ "name": "Handbags, Purses",
+ "product_tax_code": "53121600A0000"
+ },
+ {
+ "description": "Video Gaming Console - Fixed",
+ "name": "Video Gaming Console - Fixed",
+ "product_tax_code": "52161557A0000"
+ },
+ {
+ "description": "Video Cameras",
+ "name": "Video Cameras",
+ "product_tax_code": "45121515A0000"
+ },
+ {
+ "description": "Portable audio equipment that records digital music for playback",
+ "name": "Digital Music Players",
+ "product_tax_code": "52161543A0000"
+ },
+ {
+ "description": "A type of consumer electronic device used to play vinyl recordings.",
+ "name": "Audio Turntables",
+ "product_tax_code": "52161548A0000"
+ },
+ {
+ "description": "Video Gaming Console - Portable",
+ "name": "Video Gaming Console - Portable",
+ "product_tax_code": "52161558A0000"
+ },
+ {
+ "description": "A framed display designed to display preloaded digital images (jpeg or any digital image format). Has slots for flash memory cards and/or an interface for digital photo camera connection.",
+ "name": "Digital Picture Frames",
+ "product_tax_code": "52161549A0000"
+ },
+ {
+ "description": "Digital Cameras",
+ "name": "Digital Cameras",
+ "product_tax_code": "45121504A0000"
+ },
+ {
+ "description": "Mobile Phones",
+ "name": "Mobile Phones",
+ "product_tax_code": "43191501A0000"
+ },
+ {
+ "description": "A digital wristwatch that provides many other features besides timekeeping. Like a smartphone, a smartwatch has a touchscreen display, which allows you to perform actions by tapping or swiping on the screen. Smartwatches include allow access to apps, similar to apps for smartphones and tablets.",
+ "name": "Watches - Smart",
+ "product_tax_code": "54111500A0001"
+ },
+ {
+ "description": "A bicycle helmet that is NOT marketed and labeled as being intended for youth.",
+ "name": "Bicycle Helmets - Adult",
+ "product_tax_code": "46181704A0003"
+ },
+ {
+ "description": "A bicycle helmet marketed and labeled as being intended for youth.",
+ "name": "Bicycle Helmets - Youth",
+ "product_tax_code": "46181704A0002"
+ },
+ {
+ "description": "Luggage",
+ "name": "Luggage",
+ "product_tax_code": "53121500A0000"
+ },
+ {
+ "description": "Clothing - Sleep or eye mask",
+ "name": "Clothing - Sleep or eye mask",
+ "product_tax_code": "53102607A0000"
+ },
+ {
+ "description": "Clothing - Pocket protectors",
+ "name": "Clothing - Pocket protectors",
+ "product_tax_code": "53102514A0000"
+ },
+ {
+ "description": "Clothing - Button covers",
+ "name": "Clothing - Button covers",
+ "product_tax_code": "53102515A0000"
+ },
+ {
+ "description": "Shoe Inserts/Insoles",
+ "name": "Clothing - Shoe Inserts/Insoles",
+ "product_tax_code": "46182208A0000"
+ },
+ {
+ "description": "Aprons - Household/Kitchen",
+ "name": "Clothing - Aprons - Household/Kitchen",
+ "product_tax_code": "46181501A0002"
+ },
+ {
+ "description": "Hunting Vests",
+ "name": "Clothing - Hunting Vests",
+ "product_tax_code": "53103100A0003"
+ },
+ {
+ "description": "Clothing apparel/uniforms that are specific to the training and competition of various martial arts.",
+ "name": "Clothing - Martial Arts Attire",
+ "product_tax_code": "53102717A0001"
+ },
+ {
+ "description": "Clothing - Umbrellas",
+ "name": "Clothing - Umbrellas",
+ "product_tax_code": "53102505A0000"
+ },
+ {
+ "description": "Briefcases",
+ "name": "Briefcases",
+ "product_tax_code": "53121701A0000"
+ },
+ {
+ "description": "Wallets",
+ "name": "Wallets",
+ "product_tax_code": "53121600A0001"
+ },
+ {
+ "description": "Wristwatch timepieces",
+ "name": "Watches",
+ "product_tax_code": "54111500A0000"
+ },
+ {
+ "description": "Jewelry",
+ "name": "Jewelry",
+ "product_tax_code": "54100000A0000"
+ },
+ {
+ "description": "Non-prescription sunglasses",
+ "name": "Sunglasses - Non-Rx",
+ "product_tax_code": "42142905A0001"
+ },
+ {
+ "description": "Wigs, Hairpieces, Hair extensions",
+ "name": "Clothing - Wigs, Hairpieces, Hair extensions",
+ "product_tax_code": "53102500A0002"
+ },
+ {
+ "description": "Hair notions, hair clips, barrettes, hair bows, hair nets, etc.",
+ "name": "Clothing - Hair Accessories",
+ "product_tax_code": "53102500A0001"
+ },
+ {
+ "description": "Clothing - Headbands",
+ "name": "Clothing - Headbands",
+ "product_tax_code": "53102513A0000"
+ },
+ {
+ "description": "These supplies contain medication such as an antibiotic ointment. They are a labeled with a \"drug facts\" panel or a statement of active ingredients. A wound care supply is defined as an item that is applied directly to or inside a wound to absorb wound drainage, protect healing tissue, maintain a moist or dry wound environment (as appropriate), or prevent bacterial contamination. Examples include bandages, dressings, gauze, medical tape. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Wound Care Supplies - Bandages, Dressings, Gauze - Medicated",
+ "product_tax_code": "42311514A0000"
+ },
+ {
+ "description": "A wound care supply is defined as an item that is applied directly to or inside a wound to absorb wound drainage, protect healing tissue, maintain a moist or dry wound environment (as appropriate), or prevent bacterial contamination. Examples include bandages, dressings, gauze, medical tape. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Wound Care Supplies - Bandages, Dressings, Gauze",
+ "product_tax_code": "42311500A0001"
+ },
+ {
+ "description": "Toothpaste containing \"drug facts\" panel or a statement of active ingredients. These products do contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toothpaste",
+ "product_tax_code": "53131502A0000"
+ },
+ {
+ "description": "Disposable moistened cleansing wipes - non medicated. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Wipes/Cleansing Wipes",
+ "product_tax_code": "53131624A0000"
+ },
+ {
+ "description": "Toilet Paper. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toilet Paper",
+ "product_tax_code": "14111704A0000"
+ },
+ {
+ "description": "A lotion, spray, gel, foam, stick or other topical product that absorbs or reflects some of the sun's ultraviolet (UV) radiation and thus helps protect against sunburn. Sunscreen contains a \"drug facts\" label or statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Sunscreen",
+ "product_tax_code": "53131609A0000"
+ },
+ {
+ "description": "Soaps, body washes, shower gels for personal hygiene containing antibacterial. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Soaps - Antibacterial",
+ "product_tax_code": "53131608A0001"
+ },
+ {
+ "description": "Over-the-counter nicotine replacement products, including patches, gum, lozenges, sprays and inhalers. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Smoking Cessation Products",
+ "product_tax_code": "51143218A0000"
+ },
+ {
+ "description": "Lotions, moisturizers, creams, powders, sprays, etc that promote optimal skin health. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Skin Care Products- Medicated",
+ "product_tax_code": "51241200A0001"
+ },
+ {
+ "description": "A hair care product for cleansing the hair/scalp, with anti-dandruff active ingredients. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shampoo - medicated (anti-dandruff)",
+ "product_tax_code": "53131628A0001"
+ },
+ {
+ "description": "A multi-purpose skin protectorant and topical ointment. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Petroleum Jelly",
+ "product_tax_code": "53131641A0000"
+ },
+ {
+ "description": "An over-the-counter drug via RX is a substance that contains a label identifying it as a drug and including a \"drug facts\" panel or a statement of active ingredients, that can be obtained without a prescription, but is sold under prescription order of a licensed professional. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Over-the-Counter Drugs via Prescription",
+ "product_tax_code": "51030"
+ },
+ {
+ "description": "Flexible adhesive strips that attach over the bridge of the nose to lift the sides of the nose, opening the nasal passages to provide relief for congestion and snoring. The products are drug free and contain no active drug ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Nasal Breathing Strips",
+ "product_tax_code": "42312402A0001"
+ },
+ {
+ "description": "Therapeutic mouthwash, having active ingredients (such as antiseptic, or flouride) intended to help control or reduce conditions like bad breath, gingivitis, plaque, and tooth decay. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Mouthwash - Therapeutic",
+ "product_tax_code": "53131501A0000"
+ },
+ {
+ "description": "Multiple use medical thermometers for oral, temporal/forehead, or rectal body temperature diagnostics. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Thermometers - Reusable",
+ "product_tax_code": "42182200A0002"
+ },
+ {
+ "description": "One-time use medical thermometers for oral, temporal/forehead, or rectal body temperature diagnostics. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Thermometers - Disposable",
+ "product_tax_code": "42182200A0001"
+ },
+ {
+ "description": "Masks designed for one-time use to protect the wearer from contamination of breathable particles. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Medical Masks",
+ "product_tax_code": "42131713A0001"
+ },
+ {
+ "description": "A medicated skin protectorant for the lips. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Lip Balm - Medicated",
+ "product_tax_code": "53131630A0001"
+ },
+ {
+ "description": "A skin protectorant for the lips. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Lip Balm",
+ "product_tax_code": "53131630A0000"
+ },
+ {
+ "description": "Artificial devices to correct or alleviate hearing deficiencies, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aids with Prescription",
+ "product_tax_code": "42211705A0000"
+ },
+ {
+ "description": "Artificial deives to correct or alleviate hearing deficiencies, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aids without Prescription",
+ "product_tax_code": "42211705A0001"
+ },
+ {
+ "description": "Batteries specifically labeled and designed to operate hearing aid devices, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aid Batteries with Prescription",
+ "product_tax_code": "26111710A0001"
+ },
+ {
+ "description": "Batteries specifically labeled and designed to operate hearing aid devices, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hearing Aid Batteries without Prescription",
+ "product_tax_code": "26111710A0002"
+ },
+ {
+ "description": "A liquid, gel, foam, or wipe generally used to decrease infectious agents on the hands. Alcohol-based versions typically contain some combination of isopropyl alcohol, ethanol (ethyl alcohol), or n-propanol. Alcohol-free products are generally based on disinfectants, or on antimicrobial agents. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hand Sanitizers",
+ "product_tax_code": "53131626A0000"
+ },
+ {
+ "description": "Topical foams, creams, gels, etc that prevent hair loss and promote hair regrowth. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hair Loss Products",
+ "product_tax_code": "51182001A0001"
+ },
+ {
+ "description": "A collection of mixed supplies and equipment that is used to give medical treatment, often housed in durable plastic boxes, fabric pouches or in wall mounted cabinets. Exempt or low rated qualifying medicinal items (eg. OTC drugs) make up 51% or more of the value of the kit. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "First Aid Kits - 51% or more medicinal items",
+ "product_tax_code": "42172001A0002"
+ },
+ {
+ "description": "A collection of mixed supplies and equipment that is used to give medical treatment, often housed in durable plastic boxes, fabric pouches or in wall mounted cabinets. Exempt or low rated qualifying medicinal items (eg. OTC drugs) make up 50% or less of the value of the kit. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "First Aid Kits - 50% or less medicinal items",
+ "product_tax_code": "42172001A0001"
+ },
+ {
+ "description": "Over-the-counter antifungal creams, ointments or suppositories to treat yeast infections, containing a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Yeast Treatments",
+ "product_tax_code": "51302300A0001"
+ },
+ {
+ "description": "Vaginal cleaning products include douches and wipes with medication such as an antiseptic, containing a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Cleansing Solutions - Medicated",
+ "product_tax_code": "53131615A0002"
+ },
+ {
+ "description": "Vaginal cleaning products include douches and wipes. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Feminine Cleansing Solutions",
+ "product_tax_code": "53131615A0001"
+ },
+ {
+ "description": "Single use disposable gloves (latex, nitrile, vinyl, etc) that while appropriate for multiple uses, have an application in a first aid or medical setting. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Disposable Gloves",
+ "product_tax_code": "42132203A0000"
+ },
+ {
+ "description": "Personal under-arm deodorants/antiperspirants. These products do contain a \"drug facts\" panel or a statement of active ingredients, typically aluminum. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Deodorant/Antiperspirant",
+ "product_tax_code": "53131606A0000"
+ },
+ {
+ "description": "Denture adhesives are pastes, powders or adhesive pads that may be placed in/on dentures to help them stay in place. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Denture creams/adhesives",
+ "product_tax_code": "53131510A0000"
+ },
+ {
+ "description": "Toothbrushes. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Toothbrushes",
+ "product_tax_code": "53131503A0000"
+ },
+ {
+ "description": "Dental Floss/picks. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Dental Floss/picks",
+ "product_tax_code": "53131504A0000"
+ },
+ {
+ "description": "Single use cotton balls or swabs for multi-purpose use other than applying medicines and cleaning wounds, due to not being sterile. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cotton Balls/Swabs - Unsterile",
+ "product_tax_code": "42141500A0002"
+ },
+ {
+ "description": "Single use cotton balls or swabs for application of antiseptics and medications and to cleanse scratches, cuts or minor wounds. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cotton Balls/Swabs - Sterile",
+ "product_tax_code": "42141500A0001"
+ },
+ {
+ "description": "Corrective lenses, eyeglasses, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Corrective Lenses, Eyeglasses with Prescription",
+ "product_tax_code": "42142900A0001"
+ },
+ {
+ "description": "Corrective lenses, including eyeglasses and contact lenses, sold without a prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Corrective Lenses without Prescription",
+ "product_tax_code": "42142900A0002"
+ },
+ {
+ "description": "Liquid solution for lubricating/rewetting, but not disinfecting, contact lenses. This solution is applied directly to the lens, rather then inserted into the eye. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Lubricating Solutions - For lens",
+ "product_tax_code": "42142914A0001"
+ },
+ {
+ "description": "Liquid solution for lubricating/rewetting, but not disinfecting, contact lenses. This solution is applied directly to the eye. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Lubricating Solutions - For eyes",
+ "product_tax_code": "42142914A0002"
+ },
+ {
+ "description": "Contact lenses, sold under prescription order of a licensed professional. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lenses with Prescription",
+ "product_tax_code": "42142913A0000"
+ },
+ {
+ "description": "Liquid solution for cleaning and disinfecting contact lenses. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Contact Lens Disinfecting Solutions",
+ "product_tax_code": "42142914A0000"
+ },
+ {
+ "description": "A reusable pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Reusable",
+ "product_tax_code": "42142100A0002"
+ },
+ {
+ "description": "A heating pad is a pad used for warming of parts of the body in order to manage pain. Types of heating pads include electrical, chemical and hot water bottles. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Heating Pads",
+ "product_tax_code": "42142100A0001"
+ },
+ {
+ "description": "A single use pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Disposable - Medicated",
+ "product_tax_code": "42142100A0004"
+ },
+ {
+ "description": "A single use pain management supply that includes artificial ice packs, gel packs, heat wraps, etc used for pain relief. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cold or Hot Therapy Packs - Disposable",
+ "product_tax_code": "42142100A0003"
+ },
+ {
+ "description": "Baby powder is an astringent powder used for preventing diaper rash, as a spray, and for other cosmetic uses. It may be composed of talcum (in which case it is also called talcum powder) or corn starch. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Powder",
+ "product_tax_code": "53131649A0001"
+ },
+ {
+ "description": "Baby oil is an inert (typically mineral) oil for the purpose of keeping skin soft and supple. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Baby Oil",
+ "product_tax_code": "51241900A0001"
+ },
+ {
+ "description": "A cosmetic foam or gel used for shaving preparation. The purpose of shaving cream is to soften the hair by providing lubrication. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shaving Creams",
+ "product_tax_code": "53131611A0000"
+ },
+ {
+ "description": "Personal under-arm deodorants/antiperspirants containing natural ingredients and/or ingredients that are not considered drugs. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Deodorant - Natural or no active ingredients",
+ "product_tax_code": "53131606A0001"
+ },
+ {
+ "description": "A hair care product for cleansing the hair/scalp. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Shampoo",
+ "product_tax_code": "53131628A0000"
+ },
+ {
+ "description": "Various surfactant preparations to improve cleaning, enhance the enjoyment of bathing, and serve as a vehicle for cosmetic agents. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Bubble Bath, Bath Salts/Oils/Crystals",
+ "product_tax_code": "53131612A0001"
+ },
+ {
+ "description": "Cosmetic mouthwash may temporarily control bad breath and leave behind a pleasant taste, but has no chemical or biological application beyond their temporary benefit. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Mouthwash - Cosmetic",
+ "product_tax_code": "53131501A0001"
+ },
+ {
+ "description": "Teeth whitening gels, rinse, strips, trays, etc containing bleaching agents. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Teeth Whitening Kits",
+ "product_tax_code": "42151506A0000"
+ },
+ {
+ "description": "A hair care product typically applied and rinsed after shampooing that is used to improve the feel, appearance and manageability of hair. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Conditioner - Hair",
+ "product_tax_code": "53131628A0002"
+ },
+ {
+ "description": "Depilatories are cosmetic preparations used to remove hair from the skin. Chemical depilatories are available in gel, cream, lotion, aerosol, roll-on, and powder forms. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hair Removal Products",
+ "product_tax_code": "53131623A0000"
+ },
+ {
+ "description": "Breath spray is a product sprayed into the mouth and breath strips dissolve in the mouth for the purpose of eliminating halitosis. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Breath Spray/dissolvable strips",
+ "product_tax_code": "53131509A0000"
+ },
+ {
+ "description": "Lotions, moisturizers, creams, powders, sprays, etc that promote optimal skin health. These products do not contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Skin Care Products",
+ "product_tax_code": "51241200A0002"
+ },
+ {
+ "description": "Liquid drops to be placed inside the ear canal to reduce the symptoms of an ear ache, or to act as an ear drying aid, or to loosen, cleanse, and aid in the removal of ear wax. These products contain a \"drug facts\" panel or a statement of active ingredients. Examples include Ear Ache, Swimmers' Ears, and Ear Wax removal drops. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Ear Drops - Medicated",
+ "product_tax_code": "51241000A0001"
+ },
+ {
+ "description": "Topical medicated solutions for treating skin acne. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Acne Treatments",
+ "product_tax_code": "51241400A0001"
+ },
+ {
+ "description": "A skin cream forming a protective barrier to help heal and soothe diaper rash discomfort. These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Diaper Cream",
+ "product_tax_code": "51241859A0001"
+ },
+ {
+ "description": "A liquid solution typically used as a topical antiseptic. The products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Isopropyl (Rubbing) Alcohol",
+ "product_tax_code": "51471901A0000"
+ },
+ {
+ "description": "Hydrogen peroxide is a mild antiseptic used on the skin to prevent infection of minor cuts, scrapes, and burns. It may also be used as a mouth rinse to help remove mucus or to relieve minor mouth irritation (e.g., due to canker/cold sores, gingivitis). These products contain a \"drug facts\" panel or a statement of active ingredients. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Hydrogen Peroxide",
+ "product_tax_code": "51473503A0000"
+ },
+ {
+ "description": "Articles intended to be rubbed, poured, sprinkled, or sprayed on, introduced into, or otherwise applied to the human body or any part thereof for beautifying, promoting attractiveness, or altering the appearance. This category supports only the following items: Acrylic fingernail glue, Acrylic fingernails, Artificial eyelashes, Blush, Bronzer, Body glitter, Concealer, Eyelash glue, Finger/toenail decorations, Finger/toenail polish, Nail polish remover, Hair coloring, Hair mousse/gel, Hair oil, Hair spray, Hair relaxer, Hair wave treatment, Hair wax, Lip gloss, Lip liner, Lipstick, Liquid foundation, Makeup, Mascara, Nail polish remover, Powder foundation, Cologne, Perfume. This code is intended for sales directly to end consumers that are NOT healthcare providers.",
+ "name": "Cosmetics - Beautifying",
+ "product_tax_code": "53131619A0001"
+ },
+ {
+ "description": "Power cords",
+ "name": "Power cords",
+ "product_tax_code": "26121636A0000"
+ },
+ {
+ "description": "Archery accessories including quivers, releases, arrow shafts, armguards, hunting belts, bow parts, cleaning products, mounted safety equipment, scopes, sights, hunting slings, string wax, targets, target throwers, etc.",
+ "name": "Archery Accessories",
+ "product_tax_code": "49181602A0002"
+ },
+ {
+ "description": "Landscape soil, mulch, compost - residential",
+ "name": "Landscape Soil, Mulch, Compost - Residential",
+ "product_tax_code": "11121700A0001"
+ },
+ {
+ "description": "Firearms, limited to pistols, revolvers, rifles with a barrel no greater than an internal diameter of .50 caliber or a shotguns of 10 gauge or smaller.",
+ "name": "Firearms",
+ "product_tax_code": "46101500A0001"
+ },
+ {
+ "description": "Firearm accessories including repair parts, cleaning products, holsters, mounted safety equipment, choke tubes, scopes, shooting tripod/bipod/monopod, shooting bags/pouches, sights, etc.",
+ "name": "Firearm Accessories",
+ "product_tax_code": "46101506A0001"
+ },
+ {
+ "description": "Portable fuel container",
+ "name": "Portable Fuel Container",
+ "product_tax_code": "24111808A0001"
+ },
+ {
+ "description": "Hard and soft cases designed specifically for firearms equipment",
+ "name": "Gun Cases",
+ "product_tax_code": "46101801A0000"
+ },
+ {
+ "description": "Primary archery equipment including bows, crossbow, and bow strings.",
+ "name": "Archery Equipment",
+ "product_tax_code": "49181602A0001"
+ },
+ {
+ "description": "Hard and soft cases designed specifically for archery equipment.",
+ "name": "Archery Cases",
+ "product_tax_code": "46101801A0001"
+ },
+ {
+ "description": "Protective earmuffs to muffle the sound of gunfire.",
+ "name": "Hearing Protection Earmuffs",
+ "product_tax_code": "46181902A0001"
+ },
+ {
+ "description": "Ammunition for firearms with a barrel no greater than an internal diameter of .50 caliber or a shotgun of 10 gauge or smaller., including bullets, shotgun shells, and gunpowder.",
+ "name": "Ammunition",
+ "product_tax_code": "46101600A0001"
+ },
+ {
+ "description": "Bedclothes items including sheets, pillow cases, bedspreads, comforters, blankets, throws, duvet covers, pillow shams, bed skirts, mattress pad, mattress toppers, and pillows.",
+ "name": "Bedding",
+ "product_tax_code": "52121500A0000"
+ },
+ {
+ "description": "Towels used for individual drying of persons, including bath towels, beach towels, wash cloths, hand towels, fact towels, sport towels, etc.",
+ "name": "Bath towels",
+ "product_tax_code": "52121700A0000"
+ },
+ {
+ "description": "WaterSense labeled urinals.",
+ "name": "Urinals - WaterSense",
+ "product_tax_code": "30181506A0000"
+ },
+ {
+ "description": "WaterSense labeled toilets.",
+ "name": "Toilets - WaterSense",
+ "product_tax_code": "30181505A0000"
+ },
+ {
+ "description": "WaterSense labeled irrigation controllers, which act like a thermostat for your sprinkler system telling it when to turn on and off, use local weather and landscape conditions to tailor watering schedules to actual conditions on the site.",
+ "name": "Irrigation Controls - WaterSense",
+ "product_tax_code": "21102503A0001"
+ },
+ {
+ "description": "Ceiling Fans carrying an Energy Star rating.",
+ "name": "Ceiling fans - Energy Star",
+ "product_tax_code": "40101609A0000"
+ },
+ {
+ "description": "Standard incandescent light bulbs carrying an Energy Star rating.",
+ "name": "Incandescent Light Bulbs - Energy Star",
+ "product_tax_code": "39101612A0001"
+ },
+ {
+ "description": "Compact Fluorescent light (CFL) bulbs carrying an Energy Star rating.",
+ "name": "Compact Fluorescent Light Bulbs - Energy Star",
+ "product_tax_code": "39101619A0001"
+ },
+ {
+ "description": "Domestic appliance carrying an Energy Star Rating which reduces and maintains the level of humidity in the air.",
+ "name": "Dehumidifier - Energy Star",
+ "product_tax_code": "40101902A0000"
+ },
+ {
+ "description": "Domestic air conditioning (central or room) systems carrying Energy Star rating.",
+ "name": "Air conditioners - Energy Star",
+ "product_tax_code": "40101701A0000"
+ },
+ {
+ "description": "Artificial ice, blue ice, ice packs, reusable ice",
+ "name": "Artificial Ice",
+ "product_tax_code": "24121512A0000"
+ },
+ {
+ "description": "A port replicator is an attachment for a notebook computer that allows a number of devices such as a printer, large monitor, and keyboard to be simultaneously connected.",
+ "name": "Port Replicators",
+ "product_tax_code": "43211603A0000"
+ },
+ {
+ "description": "Computer Mouse/Pointing Devices",
+ "name": "Computer Mouse/Pointing Devices",
+ "product_tax_code": "43211708A0000"
+ },
+ {
+ "description": "Storage drives, hard drives, Zip drives, etc.",
+ "name": "Computer Drives",
+ "product_tax_code": "43201800A0001"
+ },
+ {
+ "description": "An in home programmable thermostat, such as a WiFi enabled smart thermostat, carrying an Energy Star rating.",
+ "name": "Programmable Wall Thermostat - Energy Star",
+ "product_tax_code": "41112209A0001"
+ },
+ {
+ "description": "Domestic gas or oil boilers for space or water heating carrying an Energy Star rating.",
+ "name": "Boilers - Energy Star",
+ "product_tax_code": "40102004A0001"
+ },
+ {
+ "description": "Domestic water heater carrying Energy Star rating.",
+ "name": "Water heater - Energy Star",
+ "product_tax_code": "40101825A0000"
+ },
+ {
+ "description": "Domestic freezers carrying Energy Star rating.",
+ "name": "Freezers- Energy Star",
+ "product_tax_code": "52141506A0000"
+ },
+ {
+ "description": "Domestic air source heat pumps carrying Energy Star rating.",
+ "name": "Heat Pumps - Energy Star",
+ "product_tax_code": "40101806A0000"
+ },
+ {
+ "description": "Domestic gas or oil furnaces carrying an Energy Star rating.",
+ "name": "Furnaces - Energy Star",
+ "product_tax_code": "40101805A0000"
+ },
+ {
+ "description": "Plywood, window film, storm shutters, hurricane shutters or other materials specifically designed to protect windows.",
+ "name": "Storm shutters/window protection devices",
+ "product_tax_code": "30151801A0001"
+ },
+ {
+ "description": "Smoke Detectors",
+ "name": "Smoke Detectors",
+ "product_tax_code": "46191501A0000"
+ },
+ {
+ "description": "Mobile phone charging device/cord",
+ "name": "Mobile Phone Charging Device/cord",
+ "product_tax_code": "43191501A0002"
+ },
+ {
+ "description": "A webcam is a video camera that feeds or streams an image or video in real time to or through a computer to a computer network, such as the Internet. Webcams are typically small cameras that sit on a desk, attach to a user's monitor, or are built into the hardware",
+ "name": "Web Camera",
+ "product_tax_code": "45121520A0000"
+ },
+ {
+ "description": "A sound card is an expansion component used in computers to receive and send audio.",
+ "name": "Sound Cards",
+ "product_tax_code": "43201502A0000"
+ },
+ {
+ "description": "Computer Speakers",
+ "name": "Computer Speakers",
+ "product_tax_code": "43211607A0000"
+ },
+ {
+ "description": "Computer Microphones",
+ "name": "Computer Microphones",
+ "product_tax_code": "43211719A0000"
+ },
+ {
+ "description": "A docking station is a hardware frame and set of electrical connection interfaces that enable a notebook computer to effectively serve as a desktop computer.",
+ "name": "Docking Stations",
+ "product_tax_code": "43211602A0000"
+ },
+ {
+ "description": "Computer Batteries",
+ "name": "Computer Batteries",
+ "product_tax_code": "26111711A0001"
+ },
+ {
+ "description": "Computer Monitor/Displays",
+ "name": "Computer Monitor/Displays",
+ "product_tax_code": "43211900A0000"
+ },
+ {
+ "description": "Computer Keyboards",
+ "name": "Computer Keyboards",
+ "product_tax_code": "43211706A0000"
+ },
+ {
+ "description": "Printer Ink",
+ "name": "Printer Ink",
+ "product_tax_code": "44103105A0000"
+ },
+ {
+ "description": "Printer Paper",
+ "name": "Printer Paper",
+ "product_tax_code": "14111507A0000"
+ },
+ {
+ "description": "Non-electric can opener",
+ "name": "Can opener - manual",
+ "product_tax_code": "52151605A0001"
+ },
+ {
+ "description": "Sheet music - Student",
+ "name": "Sheet music - Student",
+ "product_tax_code": "55101514A0000"
+ },
+ {
+ "description": "Musical instruments - Student",
+ "name": "Musical instruments - Student",
+ "product_tax_code": "60130000A0001"
+ },
+ {
+ "description": "Reference printed material commonly used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Dictionaries/Thesauruses",
+ "product_tax_code": "55101526A0001"
+ },
+ {
+ "description": "An item commonly used by a student in a course of study for artwork. This category is limited to the following items...clay and glazes, paints, paintbrushes for artwork, sketch and drawing pads, watercolors.",
+ "name": "School Art Supplies",
+ "product_tax_code": "60121200A0001"
+ },
+ {
+ "description": "A calendar based notebook to aid in outlining one's daily appointments, classes, activities, etc.",
+ "name": "Daily Planners",
+ "product_tax_code": "44112004A0001"
+ },
+ {
+ "description": "Portable self-powered or battery powered radio, two-way radio, weatherband radio.",
+ "name": "Portable Radios",
+ "product_tax_code": "43191510A0000"
+ },
+ {
+ "description": "Single or multi-pack AA, AAA, c, D, 6-volt or 9-volt batteries, excluding automobile or boat batteries.",
+ "name": "Alkaline Batteries",
+ "product_tax_code": "26111702A0000"
+ },
+ {
+ "description": "Routers",
+ "name": "Routers",
+ "product_tax_code": "43222609A0000"
+ },
+ {
+ "description": "Removable storage media such as compact disks, flash drives, thumb drives, flash memory cards.",
+ "name": "Computer Storage Media",
+ "product_tax_code": "43202000A0000"
+ },
+ {
+ "description": "Computer Printer",
+ "name": "Computer Printer",
+ "product_tax_code": "43212100A0001"
+ },
+ {
+ "description": "Portable self-powered or battery powered light sources, including flashlights, lanterns, emergency glow sticks or light sticks.",
+ "name": "Portable Light Sources",
+ "product_tax_code": "39111610A0000"
+ },
+ {
+ "description": "Canned software on tangible media that is used for non-recreational purposes, such as Antivirus, Database, Educational, Financial, Word processing, etc.",
+ "name": "Software - Prewritten, tangible media - Non-recreational",
+ "product_tax_code": "43230000A1101"
+ },
+ {
+ "description": "Personal computers, including laptops, tablets, desktops.",
+ "name": "Personal Computers",
+ "product_tax_code": "43211500A0001"
+ },
+ {
+ "description": "A device that joins pages of paper or similar material by fastening a thin metal staple through the sheets and folding the ends underneath.",
+ "name": "Staplers/Staples",
+ "product_tax_code": "44121615A0000"
+ },
+ {
+ "description": "Pins/tacks to secure papers, pictures, calendars, etc. to bulletin boards, walls, etc.",
+ "name": "Push pins/tacks",
+ "product_tax_code": "44122106A0000"
+ },
+ {
+ "description": "Bags/packs designed to carry students' books during the school day. This category does not include backpags for traveling, hiking, camping, etc.",
+ "name": "Bookbags/Backpacks - Student",
+ "product_tax_code": "53121603A0001"
+ },
+ {
+ "description": "Ground anchor systems and tie down kits for securing property against severe weather.",
+ "name": "Ground Anchor Systems and Tie-down Kits",
+ "product_tax_code": "31162108A0000"
+ },
+ {
+ "description": "An expansion card that allows the computer to send graphical information to a video display device such as a monitor, TV, or projector. Video cards are often used by gamers in place of integrated graphics due to their extra processing power and video ram.",
+ "name": "Video/Graphics Card",
+ "product_tax_code": "43201401A0000"
+ },
+ {
+ "description": "Scanners",
+ "name": "Scanners",
+ "product_tax_code": "43211711A0000"
+ },
+ {
+ "description": "Modems",
+ "name": "Modems",
+ "product_tax_code": "43222628A0000"
+ },
+ {
+ "description": "A map that could be used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Maps - Student",
+ "product_tax_code": "60103410A0001"
+ },
+ {
+ "description": "Tarps, plastic sheeting, plastic drop cloths, waterproof sheeting.",
+ "name": "Tarpaulins and Weatherproof Sheeting",
+ "product_tax_code": "24141506A0000"
+ },
+ {
+ "description": "Portable generator used to provide light or communications or power appliances during a power outage.",
+ "name": "Portable Generator",
+ "product_tax_code": "26111604A0001"
+ },
+ {
+ "description": "Headphones/Earbuds",
+ "name": "Headphones/Earbuds",
+ "product_tax_code": "52161514A0000"
+ },
+ {
+ "description": "A portable electronic device for reading digital books and periodicals.",
+ "name": "E-Book Readers",
+ "product_tax_code": "43211519A0000"
+ },
+ {
+ "description": "Mobile phone batteries",
+ "name": "Mobile Phone Batteries",
+ "product_tax_code": "43191501A0001"
+ },
+ {
+ "description": "A globe that could be used by a student in a course of study as a reference and to learn the subject being taught.",
+ "name": "Globes - Student",
+ "product_tax_code": "60104414A0001"
+ },
+ {
+ "description": "Domestic standard size refrigerators carrying Energy Star rating.",
+ "name": "Refrigerators - Energy Star",
+ "product_tax_code": "52141501A0000"
+ },
+ {
+ "description": "Non-electric food or beverage cooler.",
+ "name": "Food Storage Cooler",
+ "product_tax_code": "52152002A0001"
+ },
+ {
+ "description": "A motherboard is the physical component in a computer that contains the computer's basic circuitry and other components",
+ "name": "Motherboards",
+ "product_tax_code": "43201513A0000"
+ },
+ {
+ "description": "Calculators",
+ "name": "Calculators",
+ "product_tax_code": "44101807A0000"
+ },
+ {
+ "description": "Axes/Hatchets",
+ "name": "Axes/Hatchets",
+ "product_tax_code": "27112005A0000"
+ },
+ {
+ "description": "Water conserving products are for conserving or retaining groundwater; recharging water tables; or decreasing ambient air temperature, and so limiting water evaporation. Examples include soil sufactants, a soaker or drip-irrigation hose, a moisture control for a sprinkler or irrigation system, a rain barrel or an alternative rain and moisture collection system, a permeable ground cover surface that allows water to reach underground basins, aquifers or water collection points.",
+ "name": "Water Conserving Products",
+ "product_tax_code": "21102500A0001"
+ },
+ {
+ "description": "Domestic clothes drying appliances carrying Energy Star rating.",
+ "name": "Clothes drying machine - Energy Star",
+ "product_tax_code": "52141602A0000"
+ },
+ {
+ "description": "Software - Prewritten, electronic delivery - Business Use",
+ "name": "Software - Prewritten, electronic delivery - Business Use",
+ "product_tax_code": "43230000A9200"
+ },
+ {
+ "description": "Software - Custom, electronic delivery - Business Use",
+ "name": "Software - Custom, electronic delivery - Business Use",
+ "product_tax_code": "43230000A9201"
+ },
+ {
+ "description": "Food and Beverage - Sugar and Sugar Substitutes",
+ "name": "Food and Beverage - Sugar and Sugar Substitutes",
+ "product_tax_code": "50161900A0000"
+ },
+ {
+ "description": "Food and Beverage - Eggs and egg products",
+ "name": "Food and Beverage - Eggs and egg products",
+ "product_tax_code": "50131600A0000"
+ },
+ {
+ "description": "Food and Beverage - Coffee, coffee substitutes and tea",
+ "name": "Food and Beverage - Coffee, coffee substitutes and tea",
+ "product_tax_code": "50201700A0000"
+ },
+ {
+ "description": "Food and Beverage - Candy",
+ "name": "Food and Beverage - Candy",
+ "product_tax_code": "50161800A0000"
+ },
+ {
+ "description": "Food and Beverage - Butter, Margarine, Shortening and Cooking Oils",
+ "name": "Food and Beverage - Butter, Margarine, Shortening and Cooking Oils",
+ "product_tax_code": "50151500A0000"
+ },
+ {
+ "description": "Clothing - Facial shields",
+ "name": "Clothing - Facial shields",
+ "product_tax_code": "46181702A0001"
+ },
+ {
+ "description": "Clothing - Hard hats",
+ "name": "Clothing - Hard hats",
+ "product_tax_code": "46181701A0001"
+ },
+ {
+ "description": "Clothing - Cleanroom footwear",
+ "name": "Clothing - Cleanroom footwear",
+ "product_tax_code": "46181603A0001"
+ },
+ {
+ "description": "Clothing - Fire retardant footwear",
+ "name": "Clothing - Fire retardant footwear",
+ "product_tax_code": "46181601A0001"
+ },
+ {
+ "description": "Clothing - Protective pants",
+ "name": "Clothing - Protective pants",
+ "product_tax_code": "46181527A0001"
+ },
+ {
+ "description": "Clothing - Garters",
+ "name": "Clothing - Garters",
+ "product_tax_code": "53102509A0000"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered electronically (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, electronic delivery (support services only)",
+ "product_tax_code": "81112200A2222"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered by load and leave",
+ "name": "Software maintenance and support - Mandatory, prewritten, load and leave delivery",
+ "product_tax_code": "81112200A1310"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered electronically",
+ "name": "Software maintenance and support - Mandatory, prewritten, electronic delivery",
+ "product_tax_code": "81112200A1210"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered electronically",
+ "name": "Electronic software documentation or user manuals - Prewritten, electronic delivery",
+ "product_tax_code": "55111601A1200"
+ },
+ {
+ "description": "Clothing - Fur Ear muffs or scarves",
+ "name": "Clothing - Fur Ear muffs or scarves",
+ "product_tax_code": "53102502A0001"
+ },
+ {
+ "description": "Clothing - Safety glasses",
+ "name": "Clothing - Safety glasses",
+ "product_tax_code": "46181802A0001"
+ },
+ {
+ "description": "Software - Prewritten & delivered on tangible media",
+ "name": "Software - Prewritten, tangible media",
+ "product_tax_code": "43230000A1100"
+ },
+ {
+ "description": "Mainframe administration services\r\n",
+ "name": "Mainframe administration services\r\n",
+ "product_tax_code": "81111802A0000"
+ },
+ {
+ "description": "Co-location service",
+ "name": "Co-location service",
+ "product_tax_code": "81111814A0000"
+ },
+ {
+ "description": "Information management system for mine action IMSMA\r\n",
+ "name": "Information management system for mine action IMSMA\r\n",
+ "product_tax_code": "81111710A0000"
+ },
+ {
+ "description": "Local area network LAN maintenance or support",
+ "name": "Local area network LAN maintenance or support",
+ "product_tax_code": "81111803A0000"
+ },
+ {
+ "description": "Data center services",
+ "name": "Data center services",
+ "product_tax_code": "81112003A0000"
+ },
+ {
+ "description": "Wide area network WAN maintenance or support",
+ "name": "Wide area network WAN maintenance or support",
+ "product_tax_code": "81111804A0000"
+ },
+ {
+ "description": "Electronic data interchange EDI design\r\n",
+ "name": "Electronic data interchange EDI design\r\n",
+ "product_tax_code": "81111703A0000"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered on tangible media (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, tangible media (support services only)",
+ "product_tax_code": "81112200A1122"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered on tangible media (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, tangible media (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1121"
+ },
+ {
+ "description": "Clothing - Safety sleeves",
+ "name": "Clothing - Safety sleeves",
+ "product_tax_code": "46181516A0001"
+ },
+ {
+ "description": "Clothing - Fire retardant apparel",
+ "name": "Clothing - Fire retardant apparel",
+ "product_tax_code": "46181508A0001"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered by load and leave (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, load and leave delivery (support services only)",
+ "product_tax_code": "81112200A1322"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered by load and leave (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, load and leave delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1321"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered electronically (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, electronic delivery (support services only)",
+ "product_tax_code": "81112200A1222"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes support services only - no updates/upgrades)\r\n",
+ "product_tax_code": "81112200A2122"
+ },
+ {
+ "description": "Clothing - Protective ponchos",
+ "name": "Clothing - Protective ponchos",
+ "product_tax_code": "46181506A0001"
+ },
+ {
+ "description": "Clothing - Protective gloves",
+ "name": "Clothing - Protective gloves",
+ "product_tax_code": "46181504A0001"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Vest",
+ "name": "Clothing - Synthetic Fur Vest",
+ "product_tax_code": "53103100A0002"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered on tangible media (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, tangible media (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2121"
+ },
+ {
+ "description": "Computer graphics service\r\n",
+ "name": "Computer graphics service\r\n",
+ "product_tax_code": "81111512A0000"
+ },
+ {
+ "description": "Proprietary or licensed systems maintenance or support",
+ "name": "Proprietary or licensed systems maintenance or support",
+ "product_tax_code": "81111805A0000"
+ },
+ {
+ "description": "Software - Prewritten & delivered electronically",
+ "name": "Software - Prewritten, electronic delivery",
+ "product_tax_code": "43230000A1200"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for prewritten software including items delivered electronically (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, prewritten, electronic delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A1221"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered by load and leave (includes support services only - no updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, load and leave delivery (support services only)",
+ "product_tax_code": "81112200A2322"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered by load and leave (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, load and leave delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2321"
+ },
+ {
+ "description": "Software maintenance and support - Optional maintenance and support charges for custom software including items delivered electronically (includes software updates/upgrades)",
+ "name": "Software maintenance and support - Optional, custom, electronic delivery (incl. updates/upgrades)",
+ "product_tax_code": "81112200A2221"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered on tangible media",
+ "name": "Software maintenance and support - Mandatory, custom, tangible media",
+ "product_tax_code": "81112200A2110"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered electronically",
+ "name": "Software maintenance and support - Mandatory, custom, electronic delivery",
+ "product_tax_code": "81112200A2210"
+ },
+ {
+ "description": "Food and Beverage - Fish and seafood",
+ "name": "Food and Beverage - Fish and seafood",
+ "product_tax_code": "50121500A0000"
+ },
+ {
+ "description": "Food and Beverage - Ice cubes",
+ "name": "Food and Beverage - Ice cubes",
+ "product_tax_code": "50202302A0000"
+ },
+ {
+ "description": "Food and Beverage - Cooking Ingredients",
+ "name": "Food and Beverage - Cooking Ingredients",
+ "product_tax_code": "50181700A0000"
+ },
+ {
+ "description": "Food and Beverage - Cocoa and Cocoa products",
+ "name": "Food and Beverage - Cocoa and Cocoa products",
+ "product_tax_code": "50161511A0000"
+ },
+ {
+ "description": "Food and Beverage - Baby foods and formulas",
+ "name": "Food and Beverage - Baby foods and formulas",
+ "product_tax_code": "42231800A0000"
+ },
+ {
+ "description": "Clothing - Hazardous material protective footwear",
+ "name": "Clothing - Hazardous material protective footwear",
+ "product_tax_code": "46181602A0001"
+ },
+ {
+ "description": "Clothing - Welder gloves",
+ "name": "Clothing - Welder gloves",
+ "product_tax_code": "46181540A0001"
+ },
+ {
+ "description": "Clothing - Protective shirts",
+ "name": "Clothing - Protective shirts",
+ "product_tax_code": "46181526A0001"
+ },
+ {
+ "description": "Gift Cards",
+ "name": "Gift Cards",
+ "product_tax_code": "14111803A0001"
+ },
+ {
+ "description": "Clothing - Leg protectors",
+ "name": "Clothing - Leg protectors",
+ "product_tax_code": "46181520A0001"
+ },
+ {
+ "description": "Clothing - Protective coveralls",
+ "name": "Clothing - Protective coveralls",
+ "product_tax_code": "46181503A0001"
+ },
+ {
+ "description": "Internet or intranet client application development services\r\n",
+ "name": "Internet or intranet client application development services\r\n",
+ "product_tax_code": "81111509A0000"
+ },
+ {
+ "description": "Database design\r\n",
+ "name": "Database design\r\n",
+ "product_tax_code": "81111704A0000"
+ },
+ {
+ "description": "Computer programmers\r\n",
+ "name": "Computer programmers\r\n",
+ "product_tax_code": "81111600A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Hat",
+ "name": "Clothing - Synthetic Fur Hat",
+ "product_tax_code": "53102504A0002"
+ },
+ {
+ "description": "System or application programming management service\r\n",
+ "name": "System or application programming management service\r\n",
+ "product_tax_code": "81111511A0000"
+ },
+ {
+ "description": "Food and Beverage - Fruit",
+ "name": "Food and Beverage - Fruit",
+ "product_tax_code": "50300000A0000"
+ },
+ {
+ "description": "Food and Beverage - Vegetables",
+ "name": "Food and Beverage - Vegetables",
+ "product_tax_code": "50400000A0000"
+ },
+ {
+ "description": "Food and Beverage - Dried fruit, unsweetened",
+ "name": "Food and Beverage - Dried fruit, unsweetened",
+ "product_tax_code": "50320000A0000"
+ },
+ {
+ "description": "Food and Beverage - Snack Foods",
+ "name": "Food and Beverage - Snack Foods",
+ "product_tax_code": "50192100A0000"
+ },
+ {
+ "description": "Food and Beverage - Processed Nuts and Seeds",
+ "name": "Food and Beverage - Nuts and seeds that have been processed or treated by salting, spicing, smoking, roasting, or other means",
+ "product_tax_code": "50101716A0001"
+ },
+ {
+ "description": "Food and Beverage - Non-Alcoholic Beer, Wine",
+ "name": "Food and Beverage - Non-Alcoholic Beer, Wine",
+ "product_tax_code": "50202300A0001"
+ },
+ {
+ "description": "Food and Beverage - Ice Cream, sold in container less than one pint",
+ "name": "Food and Beverage - Ice Cream, sold in container less than one pint",
+ "product_tax_code": "50192304A0000"
+ },
+ {
+ "description": "Food and Beverage - Alcoholic beverages - Spirits",
+ "name": "Food and Beverage - Alcoholic beverages - Spirits",
+ "product_tax_code": "50202206A0000"
+ },
+ {
+ "description": "Food and Beverage - Wine",
+ "name": "Food and Beverage - Alcoholic beverages - Wine",
+ "product_tax_code": "50202203A0000"
+ },
+ {
+ "description": "Electronic content bundle - Delivered electronically with less than permanent rights of usage and streamed",
+ "name": "Electronic content bundle - Delivered electronically with less than permanent rights of usage and streamed",
+ "product_tax_code": "55111500A9220"
+ },
+ {
+ "description": "Clothing - Welding masks",
+ "name": "Clothing - Welding masks",
+ "product_tax_code": "46181703A0001"
+ },
+ {
+ "description": "Clothing - Protective wear dispenser",
+ "name": "Clothing - Protective wear dispenser",
+ "product_tax_code": "46181553A0001"
+ },
+ {
+ "description": "Clothing - Anti cut gloves",
+ "name": "Clothing - Anti cut gloves",
+ "product_tax_code": "46181536A0001"
+ },
+ {
+ "description": "Clothing - Reflective apparel or accessories",
+ "name": "Clothing - Reflective apparel or accessories",
+ "product_tax_code": "46181531A0001"
+ },
+ {
+ "description": "Clothing - Heat resistant clothing",
+ "name": "Clothing - Heat resistant clothing",
+ "product_tax_code": "46181518A0001"
+ },
+ {
+ "description": "Clothing - Cleanroom apparel",
+ "name": "Clothing - Cleanroom apparel",
+ "product_tax_code": "46181512A0001"
+ },
+ {
+ "description": "Clothing - Hazardous material protective apparel",
+ "name": "Clothing - Hazardous material protective apparel",
+ "product_tax_code": "46181509A0001"
+ },
+ {
+ "description": "Clothing - Safety vests",
+ "name": "Clothing - Safety vests",
+ "product_tax_code": "46181507A0001"
+ },
+ {
+ "description": "Clothing - Protective knee pads",
+ "name": "Clothing - Protective knee pads",
+ "product_tax_code": "46181505A0001"
+ },
+ {
+ "description": "Clothing - Bullet proof vests",
+ "name": "Clothing - Bullet proof vests",
+ "product_tax_code": "46181502A0001"
+ },
+ {
+ "description": "Clothing - Vest or waistcoats",
+ "name": "Clothing - Vest or waistcoats",
+ "product_tax_code": "53103100A0000"
+ },
+ {
+ "description": "Clothing - Prisoner uniform",
+ "name": "Clothing - Prisoner uniform",
+ "product_tax_code": "53102716A0000"
+ },
+ {
+ "description": "Clothing - Paramedic uniforms",
+ "name": "Clothing - Paramedic uniforms",
+ "product_tax_code": "53102712A0000"
+ },
+ {
+ "description": "Clothing - Ambulance officers uniforms",
+ "name": "Clothing - Ambulance officers uniforms",
+ "product_tax_code": "53102709A0000"
+ },
+ {
+ "description": "Clothing - Doctors coat",
+ "name": "Clothing - Doctors coat",
+ "product_tax_code": "53102707A0000"
+ },
+ {
+ "description": "Clothing - Sweat bands",
+ "name": "Clothing - Sweat bands",
+ "product_tax_code": "53102506A0000"
+ },
+ {
+ "description": "Clothing - Helmet parts or accessories",
+ "name": "Clothing - Helmet parts or accessories",
+ "product_tax_code": "46181706A0001"
+ },
+ {
+ "description": "Clothing - Fur Vest",
+ "name": "Clothing - Fur Vest",
+ "product_tax_code": "53103100A0001"
+ },
+ {
+ "description": "Clothing - Fur Gloves",
+ "name": "Clothing - Fur Gloves",
+ "product_tax_code": "53102503A0001"
+ },
+ {
+ "description": "Clothing - Motorcycle helmets",
+ "name": "Clothing - Motorcycle helmets",
+ "product_tax_code": "46181705A0001"
+ },
+ {
+ "description": "Operating system programming services\r\n",
+ "name": "Operating system programming services\r\n",
+ "product_tax_code": "81111505A0000"
+ },
+ {
+ "description": "Local area network communications design\r\n",
+ "name": "Local area network communications design\r\n",
+ "product_tax_code": "81111702A0000"
+ },
+ {
+ "description": "Clothing - Eye shields",
+ "name": "Clothing - Eye shields",
+ "product_tax_code": "46181803A0001"
+ },
+ {
+ "description": "Clothing - Welders helmet",
+ "name": "Clothing - Welders helmet",
+ "product_tax_code": "46181711A0001"
+ },
+ {
+ "description": "Clothing - Footwear covers",
+ "name": "Clothing - Footwear covers",
+ "product_tax_code": "46181606A0001"
+ },
+ {
+ "description": "Clothing - Cooling vest",
+ "name": "Clothing - Cooling vest",
+ "product_tax_code": "46181554A0001"
+ },
+ {
+ "description": "Clothing - Protective mesh jacket",
+ "name": "Clothing - Protective mesh jacket",
+ "product_tax_code": "46181551A0001"
+ },
+ {
+ "description": "Clothing - Protective scarf",
+ "name": "Clothing - Protective scarf",
+ "product_tax_code": "46181550A0001"
+ },
+ {
+ "description": "Clothing - Neck gaitor",
+ "name": "Clothing - Neck gaitor",
+ "product_tax_code": "46181549A0001"
+ },
+ {
+ "description": "Clothing - Welder bib",
+ "name": "Clothing - Welder bib",
+ "product_tax_code": "46181548A0001"
+ },
+ {
+ "description": "Clothing - Waterproof cap cover",
+ "name": "Clothing - Waterproof cap cover",
+ "product_tax_code": "46181547A0001"
+ },
+ {
+ "description": "Clothing - Waterproof suit",
+ "name": "Clothing - Waterproof suit",
+ "product_tax_code": "46181545A0001"
+ },
+ {
+ "description": "Clothing - Waterproof trousers or pants",
+ "name": "Clothing - Waterproof trousers or pants",
+ "product_tax_code": "46181544A0001"
+ },
+ {
+ "description": "Clothing - Protective mittens",
+ "name": "Clothing - Protective mittens",
+ "product_tax_code": "46181542A0001"
+ },
+ {
+ "description": "Clothing - Chemical resistant gloves",
+ "name": "Clothing - Chemical resistant gloves",
+ "product_tax_code": "46181541A0001"
+ },
+ {
+ "description": "Clothing - Anti vibratory gloves",
+ "name": "Clothing - Anti vibratory gloves",
+ "product_tax_code": "46181539A0001"
+ },
+ {
+ "description": "Clothing - Thermal gloves",
+ "name": "Clothing - Thermal gloves",
+ "product_tax_code": "46181538A0001"
+ },
+ {
+ "description": "Clothing - Insulated gloves",
+ "name": "Clothing - Insulated gloves",
+ "product_tax_code": "46181537A0001"
+ },
+ {
+ "description": "Clothing - Protective socks or hosiery",
+ "name": "Clothing - Protective socks or hosiery",
+ "product_tax_code": "46181535A0001"
+ },
+ {
+ "description": "Clothing - Protective wristbands",
+ "name": "Clothing - Protective wristbands",
+ "product_tax_code": "46181534A0001"
+ },
+ {
+ "description": "Clothing - Protective coats",
+ "name": "Clothing - Protective coats",
+ "product_tax_code": "46181533A0001"
+ },
+ {
+ "description": "Clothing - Insulated clothing for cold environments",
+ "name": "Clothing - Insulated clothing for cold environments",
+ "product_tax_code": "46181529A0001"
+ },
+ {
+ "description": "Clothing - Protective frock",
+ "name": "Clothing - Protective frock",
+ "product_tax_code": "46181528A0001"
+ },
+ {
+ "description": "Clothing - Safety hoods",
+ "name": "Clothing - Safety hoods",
+ "product_tax_code": "46181522A0001"
+ },
+ {
+ "description": "Clothing - Insulated or flotation suits",
+ "name": "Clothing - Insulated or flotation suits",
+ "product_tax_code": "46181517A0001"
+ },
+ {
+ "description": "Clothing - Elbow protectors",
+ "name": "Clothing - Elbow protectors",
+ "product_tax_code": "46181514A0001"
+ },
+ {
+ "description": "Clothing - Protective aprons",
+ "name": "Clothing - Protective aprons",
+ "product_tax_code": "46181501A0001"
+ },
+ {
+ "description": "Clothing - Shoes",
+ "name": "Clothing - Shoes",
+ "product_tax_code": "53111600A0000"
+ },
+ {
+ "description": "Clothing - Athletic wear",
+ "name": "Clothing - Athletic wear",
+ "product_tax_code": "53102900A0000"
+ },
+ {
+ "description": "Clothing - Folkloric clothing",
+ "name": "Clothing - Folkloric clothing",
+ "product_tax_code": "53102200A0000"
+ },
+ {
+ "description": "Clothing - Overalls or coveralls",
+ "name": "Clothing - Overalls or coveralls",
+ "product_tax_code": "53102100A0000"
+ },
+ {
+ "description": "Clothing - Dresses or skirts or saris or kimonos",
+ "name": "Clothing - Dresses or skirts or saris or kimonos",
+ "product_tax_code": "53102000A0000"
+ },
+ {
+ "description": "Clothing - Suits",
+ "name": "Clothing - Suits",
+ "product_tax_code": "53101900A0000"
+ },
+ {
+ "description": "Clothing - Sport uniform",
+ "name": "Clothing - Sport uniform",
+ "product_tax_code": "53102717A0000"
+ },
+ {
+ "description": "Clothing - Judicial robe",
+ "name": "Clothing - Judicial robe",
+ "product_tax_code": "53102714A0000"
+ },
+ {
+ "description": "Clothing - Ushers uniforms",
+ "name": "Clothing - Ushers uniforms",
+ "product_tax_code": "53102713A0000"
+ },
+ {
+ "description": "Clothing - Nurses uniforms",
+ "name": "Clothing - Nurses uniforms",
+ "product_tax_code": "53102708A0000"
+ },
+ {
+ "description": "Clothing - School uniforms",
+ "name": "Clothing - School uniforms",
+ "product_tax_code": "53102705A0000"
+ },
+ {
+ "description": "Clothing - Institutional food preparation or service attire",
+ "name": "Clothing - Institutional food preparation or service attire",
+ "product_tax_code": "53102704A0000"
+ },
+ {
+ "description": "Clothing - Police uniforms",
+ "name": "Clothing - Police uniforms",
+ "product_tax_code": "53102703A0000"
+ },
+ {
+ "description": "Clothing - Customs uniforms",
+ "name": "Clothing - Customs uniforms",
+ "product_tax_code": "53102702A0000"
+ },
+ {
+ "description": "Clothing - Bandannas",
+ "name": "Clothing - Bandannas",
+ "product_tax_code": "53102511A0000"
+ },
+ {
+ "description": "Clothing - Armbands",
+ "name": "Clothing - Armbands",
+ "product_tax_code": "53102508A0000"
+ },
+ {
+ "description": "Clothing - Caps",
+ "name": "Clothing - Caps",
+ "product_tax_code": "53102516A0000"
+ },
+ {
+ "description": "Clothing - Protective finger cots",
+ "name": "Clothing - Protective finger cots",
+ "product_tax_code": "46181530A0001"
+ },
+ {
+ "description": "Application programming services\r\n",
+ "name": "Application programming services\r\n",
+ "product_tax_code": "81111504A0000"
+ },
+ {
+ "description": "Application implementation services\r\n",
+ "name": "Application implementation services\r\n",
+ "product_tax_code": "81111508A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Ear muffs or scarves",
+ "name": "Clothing - Synthetic Fur Ear muffs or scarves",
+ "product_tax_code": "53102502A0002"
+ },
+ {
+ "description": "Clothing - Fur Poncho or Cape",
+ "name": "Clothing - Fur Poncho or Cape",
+ "product_tax_code": "53101806A0001"
+ },
+ {
+ "description": "Food and Beverage - Vitamins and Supplements - labeled with nutritional facts",
+ "name": "Food and Beverage - Vitamins and Supplements - labeled with nutritional facts",
+ "product_tax_code": "50501500A0001"
+ },
+ {
+ "description": "Food and Beverage - Nuts and seeds",
+ "name": "Food and Beverage - Nuts and seeds",
+ "product_tax_code": "50101716A0000"
+ },
+ {
+ "description": "Food and Beverage - Milk Substitutes",
+ "name": "Food and Beverage - Milk Substitutes",
+ "product_tax_code": "50151515A9000"
+ },
+ {
+ "description": "Food and Beverage - Milk and milk products",
+ "name": "Food and Beverage - Milk and milk products",
+ "product_tax_code": "50131700A0000"
+ },
+ {
+ "description": "Food and Beverage - Cheese",
+ "name": "Food and Beverage - Cheese",
+ "product_tax_code": "50131800A0000"
+ },
+ {
+ "description": "Clothing - Sandals",
+ "name": "Clothing - Sandals",
+ "product_tax_code": "53111800A0000"
+ },
+ {
+ "description": "Clothing - Pajamas or nightshirts or robes",
+ "name": "Clothing - Pajamas or nightshirts or robes",
+ "product_tax_code": "53102600A0000"
+ },
+ {
+ "description": "Clothing - Sweaters",
+ "name": "Clothing - Sweaters",
+ "product_tax_code": "53101700A0000"
+ },
+ {
+ "description": "Clothing - Slacks or trousers or shorts",
+ "name": "Clothing - Slacks or trousers or shorts",
+ "product_tax_code": "53101500A0000"
+ },
+ {
+ "description": "Clothing - Firefighter uniform",
+ "name": "Clothing - Firefighter uniform",
+ "product_tax_code": "53102718A0000"
+ },
+ {
+ "description": "Clothing - Salon smocks",
+ "name": "Clothing - Salon smocks",
+ "product_tax_code": "53102711A0000"
+ },
+ {
+ "description": "Clothing - Military uniforms",
+ "name": "Clothing - Military uniforms",
+ "product_tax_code": "53102701A0000"
+ },
+ {
+ "description": "Clothing - Heel pads",
+ "name": "Clothing - Heel pads",
+ "product_tax_code": "53112003A0000"
+ },
+ {
+ "description": "Clothing - Shoelaces",
+ "name": "Clothing - Shoelaces",
+ "product_tax_code": "53112002A0000"
+ },
+ {
+ "description": "Clothing - Infant swaddles or buntings or receiving blankets",
+ "name": "Clothing - Infant swaddles or buntings or receiving blankets",
+ "product_tax_code": "53102608A0000"
+ },
+ {
+ "description": "Clothing - Hats",
+ "name": "Clothing - Hats",
+ "product_tax_code": "53102503A0000"
+ },
+ {
+ "description": "Clothing - Ties or scarves or mufflers",
+ "name": "Clothing - Ties or scarves or mufflers",
+ "product_tax_code": "53102502A0000"
+ },
+ {
+ "description": "Clothing - Belts or suspenders",
+ "name": "Clothing - Belts or suspenders",
+ "product_tax_code": "53102501A0000"
+ },
+ {
+ "description": "Clothing - Tights",
+ "name": "Clothing - Tights",
+ "product_tax_code": "53102404A0000"
+ },
+ {
+ "description": "Clothing - Disposable youth training pants",
+ "name": "Clothing - Disposable youth training pants",
+ "product_tax_code": "53102311A0000"
+ },
+ {
+ "description": "Clothing - Undershirts",
+ "name": "Clothing - Undershirts",
+ "product_tax_code": "53102301A0000"
+ },
+ {
+ "description": "Clothing - Insulated cold weather shoe",
+ "name": "Clothing - Insulated cold weather shoe",
+ "product_tax_code": "46181610A0000"
+ },
+ {
+ "description": "Food and Beverage - Grains, Rice, Cereal",
+ "name": "Food and Beverage - Grains, Rice, Cereal",
+ "product_tax_code": "50221200A0000"
+ },
+ {
+ "description": "Clothing - Shirts",
+ "name": "Clothing - Shirts",
+ "product_tax_code": "53101600A0000"
+ },
+ {
+ "description": "Clothing - Safety boots",
+ "name": "Clothing - Safety boots",
+ "product_tax_code": "46181604A0000"
+ },
+ {
+ "description": "Clothing - Shin guards",
+ "name": "Clothing - Shin guards",
+ "product_tax_code": "49161525A0001"
+ },
+ {
+ "description": "Clothing - Athletic supporter",
+ "name": "Clothing - Athletic supporter",
+ "product_tax_code": "49161517A0001"
+ },
+ {
+ "description": "Clothing - Cleated or spiked shoes",
+ "name": "Clothing - Cleated or spiked shoes",
+ "product_tax_code": "53111900A0002"
+ },
+ {
+ "description": "Wide area network communications design\r\n",
+ "name": "Wide area network communications design\r\n\r\n",
+ "product_tax_code": "81111701A0000"
+ },
+ {
+ "description": "Systems integration design\r\n",
+ "name": "Systems integration design\r\n",
+ "product_tax_code": "81111503A0000"
+ },
+ {
+ "description": "Clothing - Bridal Gown",
+ "name": "Clothing - Bridal Gown",
+ "product_tax_code": "53101801A0004"
+ },
+ {
+ "description": "Clothing - Waterproof cap",
+ "name": "Clothing - Waterproof cap",
+ "product_tax_code": "46181546A0000"
+ },
+ {
+ "description": "Food and Beverage - Yogurt",
+ "name": "Food and Beverage - Yogurt",
+ "product_tax_code": "50131800A0001"
+ },
+ {
+ "description": "Food and Beverage - Nut Butters",
+ "name": "Food and Beverage - Nut Butters",
+ "product_tax_code": "50480000A9000"
+ },
+ {
+ "description": "Food and Beverage - Jams and Jellies",
+ "name": "Food and Beverage - Jams and Jellies",
+ "product_tax_code": "50192401A0000"
+ },
+ {
+ "description": "Food and Beverage - Honey, Maple Syrup",
+ "name": "Food and Beverage - Honey, Maple Syrup",
+ "product_tax_code": "50161509A0000"
+ },
+ {
+ "description": "Food and Beverage - Foods for Immediate Consumption",
+ "name": "Food and Beverage - Foods for Immediate Consumption",
+ "product_tax_code": "90100000A0001"
+ },
+ {
+ "description": "Food and Beverage - Bread and Flour Products",
+ "name": "Food and Beverage - Bread and Flour Products",
+ "product_tax_code": "50180000A0000"
+ },
+ {
+ "description": "Clothing - Overshoes",
+ "name": "Clothing - Overshoes",
+ "product_tax_code": "53112000A0000"
+ },
+ {
+ "description": "Clothing - Athletic footwear",
+ "name": "Clothing - Athletic footwear",
+ "product_tax_code": "53111900A0000"
+ },
+ {
+ "description": "Clothing - Slippers",
+ "name": "Clothing - Slippers",
+ "product_tax_code": "53111700A0000"
+ },
+ {
+ "description": "Clothing - Boots",
+ "name": "Clothing - Boots",
+ "product_tax_code": "53111500A0000"
+ },
+ {
+ "description": "Clothing - T-Shirts",
+ "name": "Clothing - T-Shirts",
+ "product_tax_code": "53103000A0000"
+ },
+ {
+ "description": "Clothing - Swimwear",
+ "name": "Clothing - Swimwear",
+ "product_tax_code": "53102800A0000"
+ },
+ {
+ "description": "Clothing - Coats or jackets",
+ "name": "Clothing - Coats or jackets",
+ "product_tax_code": "53101800A0000"
+ },
+ {
+ "description": "Clothing - Prison officer uniform",
+ "name": "Clothing - Prison officer uniform",
+ "product_tax_code": "53102715A0000"
+ },
+ {
+ "description": "Clothing - Corporate uniforms",
+ "name": "Clothing - Corporate uniforms",
+ "product_tax_code": "53102710A0000"
+ },
+ {
+ "description": "Clothing - Security uniforms",
+ "name": "Clothing - Security uniforms",
+ "product_tax_code": "53102706A0000"
+ },
+ {
+ "description": "Clothing - Chevrons",
+ "name": "Clothing - Chevrons",
+ "product_tax_code": "53102518A0000"
+ },
+ {
+ "description": "Clothing - Disposable work coat",
+ "name": "Clothing - Disposable work coat",
+ "product_tax_code": "53103201A0000"
+ },
+ {
+ "description": "Clothing - Bath robes",
+ "name": "Clothing - Bath robes",
+ "product_tax_code": "53102606A0000"
+ },
+ {
+ "description": "Clothing - Bib",
+ "name": "Clothing - Bib",
+ "product_tax_code": "53102521A0000"
+ },
+ {
+ "description": "Clothing - Gloves or mittens",
+ "name": "Clothing - Gloves or mittens",
+ "product_tax_code": "53102504A0000"
+ },
+ {
+ "description": "Clothing - Mouth guards",
+ "name": "Clothing - Mouth guards",
+ "product_tax_code": "42152402A0001"
+ },
+ {
+ "description": "Clothing - Boxing gloves",
+ "name": "Clothing - Boxing gloves",
+ "product_tax_code": "49171600A0000"
+ },
+ {
+ "description": "Clothing - Golf shoes",
+ "name": "Clothing - Golf shoes",
+ "product_tax_code": "53111900A0004"
+ },
+ {
+ "description": "Clothing - Bowling shoes",
+ "name": "Clothing - Bowling shoes",
+ "product_tax_code": "53111900A0003"
+ },
+ {
+ "description": "Internet or intranet server application development services\r\n",
+ "name": "Internet or intranet server application development services\r\n",
+ "product_tax_code": "81111510A0000"
+ },
+ {
+ "description": "Data conversion service\r\n",
+ "name": "Data conversion service\r\n",
+ "product_tax_code": "81112010A0000"
+ },
+ {
+ "description": "Client or server programming services\r\n",
+ "name": "Client or server programming services\r\n",
+ "product_tax_code": "81111506A0000"
+ },
+ {
+ "description": "Clothing - Ballet or tap shoes",
+ "name": "Clothing - Ballet or tap shoes",
+ "product_tax_code": "53111900A0001"
+ },
+ {
+ "description": "Clothing - Golf gloves",
+ "name": "Clothing - Golf gloves",
+ "product_tax_code": "49211606A0000"
+ },
+ {
+ "description": "Hardware as a service (HaaS)",
+ "name": "Hardware as a service (HaaS)",
+ "product_tax_code": "81161900A0000"
+ },
+ {
+ "description": "Cloud-based platform as a service (PaaS) - Personal Use",
+ "name": "Cloud-based platform as a service (PaaS) - Personal Use",
+ "product_tax_code": "81162100A0000"
+ },
+ {
+ "description": "Clothing - Panty hose",
+ "name": "Clothing - Panty hose",
+ "product_tax_code": "53102403A0000"
+ },
+ {
+ "description": "Clothing - Brassieres",
+ "name": "Clothing - Brassieres",
+ "product_tax_code": "53102304A0000"
+ },
+ {
+ "description": "Clothing - Protective sandals",
+ "name": "Clothing - Protective sandals",
+ "product_tax_code": "46181608A0000"
+ },
+ {
+ "description": "Clothing - Tuxedo or Formalwear",
+ "name": "Clothing - Tuxedo or Formalwear",
+ "product_tax_code": "53101801A0001"
+ },
+ {
+ "description": "Clothing - Lab coats",
+ "name": "Clothing - Lab coats",
+ "product_tax_code": "46181532A0000"
+ },
+ {
+ "description": "Systems planning services\r\n",
+ "name": "Systems planning services\r\n",
+ "product_tax_code": "81111707A0000"
+ },
+ {
+ "description": "Food and Beverage - Vitamins and Supplements",
+ "name": "Food and Beverage - Vitamins and Supplements - labeled with supplement facts",
+ "product_tax_code": "50501500A0000"
+ },
+ {
+ "description": "Food and Beverage - Jello and pudding mixes",
+ "name": "Food and Beverage - Jello and pudding mixes",
+ "product_tax_code": "50192404A0000"
+ },
+ {
+ "description": "Food and Beverage - Cooking spices",
+ "name": "Food and Beverage - Cooking spices",
+ "product_tax_code": "50171500A0000"
+ },
+ {
+ "description": "Food and Beverage - Alcoholic beverages - Beer/Malt Beverages",
+ "name": "Food and Beverage - Alcoholic beverages - Beer/Malt Beverages",
+ "product_tax_code": "50202201A0000"
+ },
+ {
+ "description": "Food and Beverage - Ice Cream, packaged",
+ "name": "Food and Beverage - Ice Cream, packaged",
+ "product_tax_code": "50192303A0000"
+ },
+ {
+ "description": "Electronic content bundle - Delivered electronically with permanent rights of usage and streamed",
+ "name": "Electronic content bundle - Delivered electronically with permanent rights of usage and streamed",
+ "product_tax_code": "55111500A9210"
+ },
+ {
+ "description": "Clothing - Roller skates or roller blades",
+ "name": "Clothing - Roller skates or roller blades",
+ "product_tax_code": "49221509A0000"
+ },
+ {
+ "description": "Clothing - Ice Skates",
+ "name": "Clothing - Ice Skates",
+ "product_tax_code": "49151602A0000"
+ },
+ {
+ "description": "Clothing - Life vests or preservers ",
+ "name": "Clothing - Life vests or preservers ",
+ "product_tax_code": "46161604A0000"
+ },
+ {
+ "description": "Clothing - Swim goggles",
+ "name": "Clothing - Swim goggles",
+ "product_tax_code": "49141606A0000"
+ },
+ {
+ "description": "Clothing - Bowling gloves",
+ "name": "Clothing - Bowling gloves",
+ "product_tax_code": "49211606A0002"
+ },
+ {
+ "description": "Fire Extinguishers",
+ "name": "Fire Extinguishers",
+ "product_tax_code": "46191601A0000"
+ },
+ {
+ "description": "Carbon Monoxide Detectors",
+ "name": "Carbon Monoxide Detectors",
+ "product_tax_code": "46191509A0001"
+ },
+ {
+ "description": "Ladder used for home emergency evacuation.",
+ "name": "Emergency/rescue ladder",
+ "product_tax_code": "30191501A0001"
+ },
+ {
+ "description": "Candles to be used a light source.",
+ "name": "Candles",
+ "product_tax_code": "39112604A0001"
+ },
+ {
+ "description": "Non-electric water container to store water for emergency usage.",
+ "name": "Water storage container",
+ "product_tax_code": "24111810A0001"
+ },
+ {
+ "description": "Duct Tape",
+ "name": "Duct Tape",
+ "product_tax_code": "31201501A0000"
+ },
+ {
+ "description": "Gas-powered chainsaw.",
+ "name": "Garden chainsaw",
+ "product_tax_code": "27112038A0000"
+ },
+ {
+ "description": "Chainsaw accessories include chains, lubricants, motor oil, chain sharpeners, bars, wrenches, carrying cases, repair parts, safety apparel.",
+ "name": "Chainsaw accessories",
+ "product_tax_code": "27112038A0001"
+ },
+ {
+ "description": "Shower curtain/liner used to keep water from escaping a showering area.",
+ "name": "Shower Curtain or Liner",
+ "product_tax_code": "30181607A0000"
+ },
+ {
+ "description": "Dish towels used for kitchenware drying.",
+ "name": "Dish towels",
+ "product_tax_code": "52121601A0000"
+ },
+ {
+ "description": "A bumper/liner that borders the interior walls/slats of the crib to help protect the baby.",
+ "name": "Crib bumpers/liners",
+ "product_tax_code": "56101804A0001"
+ },
+ {
+ "description": "A small mat/rug used to cover portion of bathroom floor.",
+ "name": "Bath Mats/rugs",
+ "product_tax_code": "52101507A0000"
+ },
+ {
+ "description": "A handheld computer that is capable of plotting graphs, solving simultaneous equations, and performing other tasks with variables.",
+ "name": "Graphing Calculators",
+ "product_tax_code": "44101808A0001"
+ },
+ {
+ "description": "Portable locks used by students in a school setting to prevent use, theft, vandalism or harm.",
+ "name": "Padlocks - Student",
+ "product_tax_code": "46171501A0001"
+ },
+ {
+ "description": "Domestic clothes washing appliances carrying Energy Star rating.",
+ "name": "Clothes Washing Machine - Energy Star",
+ "product_tax_code": "52141601A0000"
+ },
+ {
+ "description": "WaterSense labeled showerheads.",
+ "name": "Showerheads - WaterSense",
+ "product_tax_code": "30181801A0000"
+ },
+ {
+ "description": "Domestic dish washing appliances carrying Energy Star rating.",
+ "name": "Dishwashers - Energy Star",
+ "product_tax_code": "52141505A0000"
+ },
+ {
+ "description": "WaterSense labeled sprinkler body is the exterior shell that connects to the irrigation system piping and houses the spray nozzle that applies water on the landscape.",
+ "name": "Spray Water Sprinkler Bodies - WaterSense",
+ "product_tax_code": "21101803A0001"
+ },
+ {
+ "description": "Ropes and Cords",
+ "name": "Ropes and Cords",
+ "product_tax_code": "31151500A0000"
+ },
+ {
+ "description": "Light emitting diode (LED) bulbs carrying an Energy Star rating.",
+ "name": "LED Bulbs - Energy Star",
+ "product_tax_code": "39101628A0001"
+ },
+ {
+ "description": "WaterSense labeled bathroom sink faucets and accessories.",
+ "name": "Bathroom Faucets - WaterSense",
+ "product_tax_code": "30181702A0001"
+ },
+ {
+ "description": "Cables with industry standard connection and termination configurations used to connect various peripherals and equipment to computers.",
+ "name": "Computer Cables",
+ "product_tax_code": "43202222A0001"
+ },
+ {
+ "description": "Canned software delivered electronically that is used for non-recreational purposes, such as Antivirus, Database, Educational, Financial, Word processing, etc.",
+ "name": "Software - Prewritten, Electronic delivery - Non-recreational",
+ "product_tax_code": "43230000A1102"
+ },
+ {
+ "description": "Clothing - Baseball batting gloves",
+ "name": "Clothing - Baseball batting gloves",
+ "product_tax_code": "49211606A0001"
+ },
+ {
+ "description": "Cloud-based platform as a service (PaaS) - Business Use",
+ "name": "Cloud-based platform as a service (PaaS) - Business Use",
+ "product_tax_code": "81162100A9000"
+ },
+ {
+ "description": "Cloud-based Infrastructure as a service (IaaS) - Personal Use",
+ "name": "Cloud-based infrastructure as a service (IaaS) - Personal Use",
+ "product_tax_code": "81162200A0000"
+ },
+ {
+ "description": "Clothing - Costume Mask",
+ "name": "Clothing - Costume Mask",
+ "product_tax_code": "60122800A0000"
+ },
+ {
+ "description": "Clothing - Ski boots",
+ "name": "Clothing - Ski boots",
+ "product_tax_code": "53111900A0005"
+ },
+ {
+ "description": "Personal computer PC application design\r\n",
+ "name": "Personal computer PC application design\r\n",
+ "product_tax_code": "81111502A0000"
+ },
+ {
+ "description": "Network planning services\r\n",
+ "name": "Network planning services\r\n",
+ "product_tax_code": "81111706A0000"
+ },
+ {
+ "description": "ERP or database applications programming services\r\n",
+ "name": "ERP or database applications programming services\r\n",
+ "product_tax_code": "81111507A0000"
+ },
+ {
+ "description": "Content or data classification services\r\n",
+ "name": "Content or data classification services\r\n",
+ "product_tax_code": "81112009A0000"
+ },
+ {
+ "description": "Clothing - Prom Dress",
+ "name": "Clothing - Prom Dress",
+ "product_tax_code": "53101801A0003"
+ },
+ {
+ "description": "Clothing - Formal Dress",
+ "name": "Clothing - Formal Dress",
+ "product_tax_code": "53101801A0002"
+ },
+ {
+ "description": "Clothing - Handkerchiefs",
+ "name": "Clothing - Handkerchiefs",
+ "product_tax_code": "53102512A0000"
+ },
+ {
+ "description": "Clothing - Protective lens",
+ "name": "Clothing - Protective lens",
+ "product_tax_code": "46181811A0001"
+ },
+ {
+ "description": "Clothing - Body shaping garments",
+ "name": "Clothing - Body shaping garments",
+ "product_tax_code": "53102307A0000"
+ },
+ {
+ "description": "Clothing - Underpants",
+ "name": "Clothing - Underpants",
+ "product_tax_code": "53102303A0000"
+ },
+ {
+ "description": "Clothing - Waterproof boot",
+ "name": "Clothing - Waterproof boot",
+ "product_tax_code": "46181611A0000"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered by load and leave",
+ "name": "Electronic software documentation or user manuals - Prewritten, load and leave delivery",
+ "product_tax_code": "55111601A1300"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered on tangible media",
+ "name": "Electronic software documentation or user manuals - Custom, tangible media",
+ "product_tax_code": "55111601A2100"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered by load and leave",
+ "name": "Electronic software documentation or user manuals - Custom, load and leave delivery",
+ "product_tax_code": "55111601A2300"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For custom software & delivered electronically",
+ "name": "Electronic software documentation or user manuals - Custom, electronic delivery",
+ "product_tax_code": "55111601A2200"
+ },
+ {
+ "description": "Electronic publications and music - Streamed",
+ "name": "Electronic publications and music - Streamed",
+ "product_tax_code": "55111500A1500"
+ },
+ {
+ "description": "Electronic publications and music - Delivered electronically with permanent rights of usage",
+ "name": "Electronic publications and music - Delivered electronically with permanent rights of usage",
+ "product_tax_code": "55111500A1210"
+ },
+ {
+ "description": "Electronic publications and music - Delivered electronically with less than permanent rights of usage",
+ "name": "Electronic publications and music - Delivered electronically with less than permanent rights of usage",
+ "product_tax_code": "55111500A1220"
+ },
+ {
+ "description": "Software - Custom & delivered on tangible media",
+ "name": "Software - Custom, tangible media",
+ "product_tax_code": "43230000A2100"
+ },
+ {
+ "description": "Software - Prewritten & delivered by digital keycode printed on tangible media",
+ "name": "Software - Prewritten, delivered by digital keycode printed on tangible media",
+ "product_tax_code": "43230000A1400"
+ },
+ {
+ "description": "Software - Prewritten & delivered by load and leave",
+ "name": "Software - Prewritten, load and leave delivery",
+ "product_tax_code": "43230000A1300"
+ },
+ {
+ "description": "Internet cloud storage service\r\n",
+ "name": "Internet cloud storage service\r\n",
+ "product_tax_code": "81111513A0000"
+ },
+ {
+ "description": "Computer or network or internet security\r\n",
+ "name": "Computer or network or internet security\r\n",
+ "product_tax_code": "81111801A0000"
+ },
+ {
+ "description": "Document scanning service\r\n",
+ "name": "Document scanning service\r\n",
+ "product_tax_code": "81112005A0000"
+ },
+ {
+ "description": "Cloud-based software as a service (SaaS) - Business Use",
+ "name": "Cloud-based software as a service (SaaS) - Business Use",
+ "product_tax_code": "81162000A9000"
+ },
+ {
+ "description": "Demining geographical or geospatial information system GIS\r\n",
+ "name": "Demining geographical or geospatial information system GIS\r\n",
+ "product_tax_code": "81111709A0000"
+ },
+ {
+ "description": "Content or data standardization services\r\n",
+ "name": "Content or data standardization services\r\n",
+ "product_tax_code": "81112007A0000"
+ },
+ {
+ "description": "Data processing or preparation services\r\n",
+ "name": "Data processing or preparation services\r\n",
+ "product_tax_code": "81112002A0000"
+ },
+ {
+ "description": "Database analysis service\r\n",
+ "name": "Database analysis service\r\n",
+ "product_tax_code": "81111806A0000"
+ },
+ {
+ "description": "Electronic software documentation or user manuals - For prewritten software & delivered on tangible media",
+ "name": "Electronic software documentation or user manuals - Prewritten, tangible media",
+ "product_tax_code": "55111601A1100"
+ },
+ {
+ "description": "Cloud-based software as a service (SaaS) - Personal Use",
+ "name": "Cloud-based software as a service (SaaS) - Personal Use",
+ "product_tax_code": "81162000A0000"
+ },
+ {
+ "description": "Clothing - Costume",
+ "name": "Clothing - Costume",
+ "product_tax_code": "60141401A0000"
+ },
+ {
+ "description": "Online data processing service\r\n",
+ "name": "Online data processing service\r\n",
+ "product_tax_code": "81112001A0000"
+ },
+ {
+ "description": "System usability services\r\n",
+ "name": "System usability services\r\n",
+ "product_tax_code": "81111820A0000"
+ },
+ {
+ "description": "Services that provide both essential proactive and reactive operations and maintenance support.",
+ "name": "IT Support Services",
+ "product_tax_code": "81111811A0000"
+ },
+ {
+ "description": "System analysis service\r\n",
+ "name": "System analysis service\r\n",
+ "product_tax_code": "81111808A0000"
+ },
+ {
+ "description": "Data storage service\r\n",
+ "name": "Data storage service\r\n",
+ "product_tax_code": "81112006A0000"
+ },
+ {
+ "description": "Quality assurance services\r\n",
+ "name": "Quality assurance services\r\n",
+ "product_tax_code": "81111819A0000"
+ },
+ {
+ "description": "Software - Custom & delivered by load & leave",
+ "name": "Software - Custom, load and leave delivery",
+ "product_tax_code": "43230000A2300"
+ },
+ {
+ "description": "Food and Beverage - Meat Sticks, Meat Jerky",
+ "name": "Food and Beverage - Meat Sticks, Meat Jerky",
+ "product_tax_code": "50112000A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Poncho or Cape",
+ "name": "Clothing - Synthetic Fur Poncho or Cape",
+ "product_tax_code": "53101806A0002"
+ },
+ {
+ "description": "Clothing - Wetsuit",
+ "name": "Clothing - Wetsuit",
+ "product_tax_code": "49141506A0000"
+ },
+ {
+ "description": "Cloud-based business process as a service - Business Use",
+ "name": "Cloud-based business process as a service - Business Use",
+ "product_tax_code": "81162300A9000"
+ },
+ {
+ "description": "Cloud-based infrastructure as a service (IaaS) - Business Use",
+ "name": "Cloud-based infrastructure as a service (IaaS) - Business Use",
+ "product_tax_code": "81162200A9000"
+ },
+ {
+ "description": "Clothing - Belt Buckle",
+ "name": "Clothing - Belt Buckle",
+ "product_tax_code": "53102501A0001"
+ },
+ {
+ "description": "Clothing - Shower Cap",
+ "name": "Clothing - Shower Cap",
+ "product_tax_code": "53131601A0000"
+ },
+ {
+ "description": "Clothing - Eye shield garters",
+ "name": "Clothing - Eye shield garters",
+ "product_tax_code": "46181809A0001"
+ },
+ {
+ "description": "Clothing - Socks",
+ "name": "Clothing - Socks",
+ "product_tax_code": "53102402A0000"
+ },
+ {
+ "description": "Clothing - Stockings",
+ "name": "Clothing - Stockings",
+ "product_tax_code": "53102401A0000"
+ },
+ {
+ "description": "Food and Beverage - Meat and meat products",
+ "name": "Food and Beverage - Meat and meat products",
+ "product_tax_code": "50110000A0000"
+ },
+ {
+ "description": "Clothing - Slips",
+ "name": "Clothing - Slips",
+ "product_tax_code": "53102302A0000"
+ },
+ {
+ "description": "Clothing - Goggle protective covers",
+ "name": "Clothing - Goggle protective covers",
+ "product_tax_code": "46181808A0001"
+ },
+ {
+ "description": "Clothing - Goggles",
+ "name": "Clothing - Goggles",
+ "product_tax_code": "46181804A0001"
+ },
+ {
+ "description": "Clothing - Football receiver gloves",
+ "name": "Clothing - Football receiver gloves",
+ "product_tax_code": "49211606A0004"
+ },
+ {
+ "description": "Disaster recovery services",
+ "name": "Disaster recovery services",
+ "product_tax_code": "81112004A0000"
+ },
+ {
+ "description": "Clothing - Mountain climbing boot",
+ "name": "Clothing - Mountain climbing boot",
+ "product_tax_code": "46181613A0000"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for prewritten software including items delivered on tangible media",
+ "name": "Software maintenance and support - Mandatory, prewritten, tangible media",
+ "product_tax_code": "81112200A1110"
+ },
+ {
+ "description": "Clothing - Military boot",
+ "name": "Clothing - Military boot",
+ "product_tax_code": "46181612A0000"
+ },
+ {
+ "description": "Carbonated beverages marketed as energy drinks, carrying a Supplement Facts Label, that contain a blend of energy enhancing vitamins, minerals, herbals, stimulants, etc.",
+ "name": "Energy Beverages - Carbonated - with Supplement Facts Label",
+ "product_tax_code": "50202309A0001"
+ },
+ {
+ "description": "Non-carbonated beverages marketed as energy drinks, carrying a Supplement Facts Label, that contain a blend of energy enhancing vitamins, minerals, herbals, stimulants, etc.",
+ "name": "Energy Beverages - Non-Carbonated - with Supplement Facts Label",
+ "product_tax_code": "50202309A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising 90% or more of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food 90% or more - Food is all Candy",
+ "product_tax_code": "50193400A0001"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising less 90% or more of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food 90% or more",
+ "product_tax_code": "50193400A0000"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 76% and 89% of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food between 76% and 89% - Food is all Candy",
+ "product_tax_code": "50193400A0005"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 76% and 89% of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food between 76% and 89%",
+ "product_tax_code": "50193400A0004"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 50% and 75% of the overall value of the bundle, where all food consists of candy (not containing flour).",
+ "name": "Food/TPP Bundle - with Food between 50% and 75% - Food is all Candy",
+ "product_tax_code": "50193400A0003"
+ },
+ {
+ "description": "Food bundle or basket containing food staples combined with tangible personal property, with the food comprising between 50% and 75% of the overall value of the bundle.",
+ "name": "Food/TPP Bundle - with Food between 50% and 75%",
+ "product_tax_code": "50193400A0002"
+ },
+ {
+ "description": "Food/TPP Bundle - with Food less than 50%",
+ "name": "Food/TPP Bundle - with Food less than 50%",
+ "product_tax_code": "50193400A0006"
+ },
+ {
+ "description": "Ready to drink beverages, not containing milk, formulated and labled for their nutritional value, such as increased caloric or protein intake and containing natrual or artificial sweeteners.",
+ "name": "Nutritional Supplement/protein drinks, shakes - contains no milk",
+ "product_tax_code": "50501703A0000"
+ },
+ {
+ "description": "Ready to drink beverages, containing milk, formulated and labled for their nutritional value, such as increased caloric or protein intake.",
+ "name": "Nutritional Supplement/protein drinks, shakes - contains milk",
+ "product_tax_code": "50501703A0001"
+ },
+ {
+ "description": "Powdered mixes to be reconstituted into a drinkable beverage using water.",
+ "name": "Powdered Drink Mixes - to be mixed with water",
+ "product_tax_code": "50202311A0000"
+ },
+ {
+ "description": "Powdered mixes to be reconstituted into a drinkable beverage using milk or a milk substitute.",
+ "name": "Powdered Drink Mixes - to be mixed with milk",
+ "product_tax_code": "50202311A0001"
+ },
+ {
+ "description": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing no flour",
+ "name": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing no flour",
+ "product_tax_code": "50221202A0002"
+ },
+ {
+ "description": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing flour",
+ "name": "Food and Beverage - Granola Bars, Cereal Bars, Energy Bars, Protein Bars containing flour",
+ "product_tax_code": "50221202A0001"
+ },
+ {
+ "description": "Nutritional supplement in powder form, dairy based or plant based, focused on increasing ones intake of protein for various benefits.",
+ "name": "Protein Powder",
+ "product_tax_code": "50501703A0002"
+ },
+ {
+ "description": "Ready to drink non-carbonated beverage containing tea with natural or artificial sweeteners.",
+ "name": "Bottled tea - non-carbonated - sweetened",
+ "product_tax_code": "50201712A0003"
+ },
+ {
+ "description": "Ready to drink non-carbonated beverage containing tea without natural or artificial sweeteners.",
+ "name": "Bottled tea - non-carbonated - unsweetened",
+ "product_tax_code": "50201712A0000"
+ },
+ {
+ "description": "Ready to drink carbonated beverage containing tea with natural or artificial sweeteners.",
+ "name": "Bottled tea - carbonated - sweetened",
+ "product_tax_code": "50201712A0002"
+ },
+ {
+ "description": "Ready to drink carbonated beverage containing tea and without any natural or artificial sweeteners.",
+ "name": "Bottled tea - carbonated - unsweetened",
+ "product_tax_code": "50201712A0001"
+ },
+ {
+ "description": "Ready to drink coffee based beverage containing milk or milk substitute.",
+ "name": "Bottled coffee - containing milk or milk substitute",
+ "product_tax_code": "50201708A0002"
+ },
+ {
+ "description": "Ready to drink coffee based beverage not containing milk, containing natural or artificial sweetener.",
+ "name": "Bottled coffee - no milk - sweetened",
+ "product_tax_code": "50201708A0001"
+ },
+ {
+ "description": "Ready to drink coffee based beverage containing neither milk nor natural or artificial sweeteners.",
+ "name": "Bottled coffee - no milk - unsweetened",
+ "product_tax_code": "50201708A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 51-69% vegetable juice",
+ "product_tax_code": "50202306A0008"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 1-9% fruit juice",
+ "product_tax_code": "50202306A0001"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 70-99% fruit juice",
+ "product_tax_code": "50202304A0010"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 51-69% vegetable juice",
+ "product_tax_code": "50202304A0009"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 25-50% vegetable juice",
+ "product_tax_code": "50202304A0007"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 10-24% fruit juice",
+ "product_tax_code": "50202304A0004"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 70-99% vegetable juice",
+ "product_tax_code": "50202304A0011"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and zero natural fruit or vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - No fruit or vegetable juice",
+ "product_tax_code": "50202304A0001"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 51-69% fruit juice",
+ "product_tax_code": "50202304A0008"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 1 -9% vegetable juice",
+ "product_tax_code": "50202304A0003"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 1-9% fruit juice",
+ "product_tax_code": "50202304A0002"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 10-24% vegetable juice",
+ "product_tax_code": "50202304A0005"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural fruit juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 25-50% fruit juice",
+ "product_tax_code": "50202304A0006"
+ },
+ {
+ "description": "Non-carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 100% natural fruit or vegetable juice. This does not include flavored water. This does include sweetened cocktail mixes that can be combined with alcohol. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Non-Carbonated - 100% fruit or vegetable juice",
+ "product_tax_code": "50202304A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and zero natural fruit or vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - No fruit or vegetable juice",
+ "product_tax_code": "50202306A0000"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 70-99% vegetable juice",
+ "product_tax_code": "50202306A0010"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 70 - 99% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 70-99% fruit juice",
+ "product_tax_code": "50202306A0009"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 51 - 69% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 51-69% fruit juice",
+ "product_tax_code": "50202306A0007"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural vegetable juice. This does not flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 25-50% vegetable juice",
+ "product_tax_code": "50202306A0006"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 25 - 50% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 25-50% fruit juice",
+ "product_tax_code": "50202306A0005"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 100% natural fruit or vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 100% fruit or vegetable juice",
+ "product_tax_code": "50202306A0011"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 10-24% vegetable juice",
+ "product_tax_code": "50202306A0004"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 10 - 24% natural fruit juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 10-24% fruit juice",
+ "product_tax_code": "50202306A0003"
+ },
+ {
+ "description": "Carbonated nonalcoholic beverages that contain natural or artificial sweeteners, and 1 - 9% natural vegetable juice. This does not include flavored carbonated water. This does include beverages marketed as energy drinks that carry a Nutrition Facts label and contain a blend of energy enhancing ingredients.",
+ "name": "Soft Drinks - Carbonated - 1 -9% vegetable juice",
+ "product_tax_code": "50202306A0002"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, non-carbonated. Does not include distilled water.",
+ "name": "Bottled Water",
+ "product_tax_code": "50202301A0000"
+ },
+ {
+ "description": "Bottled Water for human consumption, containing natural or artificial sweeteners, non-carbonated.",
+ "name": "Bottled Water - Flavored",
+ "product_tax_code": "50202301A0001"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, carbonated naturally. Includes carbonated waters containing only natural flavors or essences.",
+ "name": "Bottled Water - Carbonated Naturally",
+ "product_tax_code": "50202301A0003"
+ },
+ {
+ "description": "Bottled Water for human consumption, unsweetened, carbonated artificially during bottling process. Includes carbonated waters containing only natural flavors or essences.",
+ "name": "Bottled Water - Carbonated Artificially",
+ "product_tax_code": "50202301A0002"
+ },
+ {
+ "description": "Bottled Water for human consumption, containing natural or artificial sweeteners, carbonated.",
+ "name": "Bottled Water - Carbonated - Sweetened",
+ "product_tax_code": "50202301A0004"
+ },
+ {
+ "description": "Clothing - Sequins for use in clothing",
+ "name": "Clothing - Sequins for use in clothing",
+ "product_tax_code": "60123900A0000"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Gloves",
+ "name": "Clothing - Synthetic Fur Gloves",
+ "product_tax_code": "53102503A0002"
+ },
+ {
+ "description": "Clothing - Synthetic Fur Coat or Jacket",
+ "name": "Clothing - Synthetic Fur Coat or Jacket",
+ "product_tax_code": "53101800A0002"
+ },
+ {
+ "description": "Clothing - Fur Hat",
+ "name": "Clothing - Fur Hat",
+ "product_tax_code": "53102504A0001"
+ },
+ {
+ "description": "Clothing - Fur Coat or Jacket",
+ "name": "Clothing - Fur Coat or Jacket",
+ "product_tax_code": "53101800A0001"
+ },
+ {
+ "description": "Cloud-based business process as a service",
+ "name": "Cloud-based business process as a service - Personal Use",
+ "product_tax_code": "81162300A0000"
+ },
+ {
+ "description": "Clothing - Shoulder pads for sports",
+ "name": "Clothing - Shoulder pads for sports",
+ "product_tax_code": "46181506A0002"
+ },
+ {
+ "description": "Mainframe software applications design\r\n",
+ "name": "Mainframe software applications design\r\n",
+ "product_tax_code": "81111501A0000"
+ },
+ {
+ "description": "Clothing - Safety shoes",
+ "name": "Clothing - Safety shoes",
+ "product_tax_code": "46181605A0000"
+ },
+ {
+ "description": "Clothing - Protective hood",
+ "name": "Clothing - Protective hood",
+ "product_tax_code": "46181710A0001"
+ },
+ {
+ "description": "Clothing - Face protection kit",
+ "name": "Clothing - Face protection kit",
+ "product_tax_code": "46181709A0001"
+ },
+ {
+ "description": "Clothing - Protective hair net",
+ "name": "Clothing - Protective hair net",
+ "product_tax_code": "46181708A0001"
+ },
+ {
+ "description": "Clothing - Facial shields parts or accessories",
+ "name": "Clothing - Facial shields parts or accessories",
+ "product_tax_code": "46181707A0001"
+ },
+ {
+ "description": "Clothing - Safety helmets",
+ "name": "Clothing - Safety helmets",
+ "product_tax_code": "46181704A0001"
+ },
+ {
+ "description": "Clothing - Poncho",
+ "name": "Clothing - Poncho",
+ "product_tax_code": "53101806A0000"
+ },
+ {
+ "description": "Clothing - Protective insole",
+ "name": "Clothing - Protective insole",
+ "product_tax_code": "46181609A0000"
+ },
+ {
+ "description": "Clothing - Protective clogs",
+ "name": "Clothing - Protective clogs",
+ "product_tax_code": "46181607A0000"
+ },
+ {
+ "description": "Clothing - Waterproof jacket or raincoat",
+ "name": "Clothing - Waterproof jacket or raincoat",
+ "product_tax_code": "46181543A0000"
+ },
+ {
+ "description": "Systems architecture\r\n",
+ "name": "Systems architecture\r\n",
+ "product_tax_code": "81111705A0000"
+ },
+ {
+ "description": "System installation service\r\n",
+ "name": "System installation service\r\n",
+ "product_tax_code": "81111809A0000"
+ },
+ {
+ "description": "Software maintenance and support - Mandatory maintenance and support charges for custom software including items delivered by load and leave",
+ "name": "Software maintenance and support - Mandatory, custom, load and leave delivery",
+ "product_tax_code": "81112200A2310"
+ },
+ {
+ "description": "Software coding service\r\n",
+ "name": "Software coding service\r\n",
+ "product_tax_code": "81111810A0000"
+ },
+ {
+ "description": "Software - Custom & delivered electronically",
+ "name": "Software - Custom, electronic delivery",
+ "product_tax_code": "43230000A2200"
+ },
+ {
+ "description": "Bathing suits and swim suits",
+ "name": "Clothing - Swimwear",
+ "product_tax_code": "20041"
+ },
+ {
+ "description": "Miscellaneous services which are not subject to a service-specific tax levy. This category will only treat services as taxable if the jurisdiction taxes services generally.",
+ "name": "General Services",
+ "product_tax_code": "19000"
+ },
+ {
+ "description": "Services provided to educate users on the proper use of a product. Live training in person",
+ "name": "Training Services - Live",
+ "product_tax_code": "19004"
+ },
+ {
+ "description": "Admission charges associated with entry to an event.",
+ "name": "Admission Services",
+ "product_tax_code": "19003"
+ },
+ {
+ "description": "Service of providing usage of a parking space.",
+ "name": "Parking Services",
+ "product_tax_code": "19002"
+ },
+ {
+ "description": "A charge separately stated from any sale of the product itself for the installation of tangible personal property. This a labor charge, with any non-separately stated property transferred in performing the service considered inconsequential.",
+ "name": "Installation Services",
+ "product_tax_code": "10040"
+ },
+ {
+ "description": "Services rendered for advertising which do not include the exchange of tangible personal property.",
+ "name": "Advertising Services",
+ "product_tax_code": "19001"
+ },
+ {
+ "description": "Digital products transferred electronically, meaning obtained by the purchaser by means other than tangible storage media.",
+ "name": "Digital Goods",
+ "product_tax_code": "31000"
+ },
+ {
+ "description": " All human wearing apparel suitable for general use",
+ "name": "Clothing",
+ "product_tax_code": "20010"
+ },
+ {
+ "description": "An over-the-counter drug is a substance that contains a label identifying it as a drug and including a \"drug facts\" panel or a statement of active ingredients, that can be obtained without a prescription. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body.",
+ "name": "Over-the-Counter Drugs",
+ "product_tax_code": "51010"
+ },
+ {
+ "description": "A substance that can only be obtained via a prescription of a licensed professional. A drug is a compound, substance, or preparation, and any component thereof, not including food or food ingredients, dietary supplements, or alcoholic beverages, that is: recognized in the official United States pharmacopoeia, official homeopathic pharmacopoeia of the United States, or official national formulary, and supplement to any of them; intended for use in the diagnosis, cure, mitigation, treatment, or prevention of disease; or intended to affect the structure or any function of the body. A drug can be intended for internal (ingestible, implant, injectable) or external (topical) application to the human body.",
+ "name": "Prescription Drugs",
+ "product_tax_code": "51020"
+ },
+ {
+ "description": "Food for humans consumption, unprepared",
+ "name": "Food & Groceries",
+ "product_tax_code": "40030"
+ },
+ {
+ "description": "Pre-written software, delivered electronically, but access remotely.",
+ "name": "Software as a Service",
+ "product_tax_code": "30070"
+ },
+ {
+ "description": "Periodicals, printed, sold by subscription",
+ "name": "Magazines & Subscriptions",
+ "product_tax_code": "81300"
+ },
+ {
+ "description": "Books, printed",
+ "name": "Books",
+ "product_tax_code": "81100"
+ },
+ {
+ "description": "Periodicals, printed, sold individually",
+ "name": "Magazine",
+ "product_tax_code": "81310"
+ },
+ {
+ "description": "Textbooks, printed",
+ "name": "Textbook",
+ "product_tax_code": "81110"
+ },
+ {
+ "description": "Religious books and manuals, printed",
+ "name": "Religious books",
+ "product_tax_code": "81120"
+ },
+ {
+ "description": "Non-food dietary supplements",
+ "name": "Supplements",
+ "product_tax_code": "40020"
+ },
+ {
+ "description": "Candy",
+ "name": "Candy",
+ "product_tax_code": "40010"
+ },
+ {
+ "description": "Soft drinks. Soda and similar drinks. Does not include water, juice, or milk.",
+ "name": "Soft Drinks",
+ "product_tax_code": "40050"
+ },
+ {
+ "description": "Bottled water for human consumption.",
+ "name": "Bottled Water",
+ "product_tax_code": "40060"
+ },
+ {
+ "description": "Ready to eat foods intended to be consumed on site by humans. Foods not considered to be Food & Grocery (not food for home consumption or food which requires further preparation to consume).",
+ "name": "Prepared Foods",
+ "product_tax_code": "41000"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py
index 24ab1cf049f..25982b81227 100644
--- a/erpnext/regional/united_states/setup.py
+++ b/erpnext/regional/united_states/setup.py
@@ -2,13 +2,44 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+import os
+import json
+from frappe.permissions import add_permission, update_permission_property
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
def setup(company=None, patch=True):
+ # Company independent fixtures should be called only once at the first company setup
+ if frappe.db.count('Company', {'country': 'United States'}) <=1:
+ setup_company_independent_fixtures(patch=patch)
+
+def setup_company_independent_fixtures(company=None, patch=True):
+ add_product_tax_categories()
make_custom_fields()
+ add_permissions()
+ frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False)
add_print_formats()
+# Product Tax categories imported from taxjar api
+def add_product_tax_categories():
+ with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f:
+ tax_categories = json.loads(f.read())
+ create_tax_categories(tax_categories['categories'])
+
+def create_tax_categories(data):
+ for d in data:
+ tax_category = frappe.new_doc('Product Tax Category')
+ tax_category.description = d.get("description")
+ tax_category.product_tax_code = d.get("product_tax_code")
+ tax_category.category_name = d.get("name")
+ try:
+ tax_category.db_insert()
+ except frappe.DuplicateEntryError:
+ pass
+
+
def make_custom_fields(update=True):
custom_fields = {
'Supplier': [
@@ -30,10 +61,29 @@ def make_custom_fields(update=True):
'Quotation': [
dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges',
label='Is customer exempted from sales tax?')
+ ],
+ 'Sales Invoice Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category',
+ label='Product Tax Category', fetch_from='item_code.product_tax_category'),
+ dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount',
+ label='Tax Collectable', read_only=1),
+ dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable',
+ label='Taxable Amount', read_only=1)
+ ],
+ 'Item': [
+ dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category',
+ label='Product Tax Category')
]
}
create_custom_fields(custom_fields, update=update)
+def add_permissions():
+ doctype = "Product Tax Category"
+ for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'):
+ add_permission(doctype, role, 0)
+ update_permission_property(doctype, role, 0, 'write', 1)
+ update_permission_property(doctype, role, 0, 'create', 1)
+
def add_print_formats():
frappe.reload_doc("regional", "print_format", "irs_1099_form")
frappe.db.set_value("Print Format", "IRS 1099 Form", "disabled", 0)
diff --git a/erpnext/regional/united_states/test_united_states.py b/erpnext/regional/united_states/test_united_states.py
index 513570ed6df..19e9a3546f8 100644
--- a/erpnext/regional/united_states/test_united_states.py
+++ b/erpnext/regional/united_states/test_united_states.py
@@ -1,8 +1,11 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+
+import frappe
+
from erpnext.regional.report.irs_1099.irs_1099 import execute as execute_1099_report
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.py b/erpnext/restaurant/doctype/restaurant/restaurant.py
index 0bb7b692c75..486afc3a11e 100644
--- a/erpnext/restaurant/doctype/restaurant/restaurant.py
+++ b/erpnext/restaurant/doctype/restaurant/restaurant.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class Restaurant(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
index adce5c73352..5b78bb2f45a 100644
--- a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
+++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'restaurant',
diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
index 3ba7f5785eb..574cd1f9e4a 100644
--- a/erpnext/restaurant/doctype/restaurant/test_restaurant.py
+++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
test_records = [
diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
index 952c46769b7..632f4850d8a 100644
--- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
+++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class RestaurantMenu(Document):
def validate(self):
for d in self.items:
diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
index 29f95fd8b1f..00cbf358d6f 100644
--- a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
+++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py
@@ -3,9 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
test_records = [
dict(doctype='Item', item_code='Food Item 1',
item_group='Products', is_stock_item=0),
diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
index cc86bb3165e..5d095f49a8e 100644
--- a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
+++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class RestaurantMenuItem(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
index 357deaac007..1ed5921f350 100644
--- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
+++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py
@@ -3,11 +3,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, json
-from frappe.model.document import Document
+
+import json
+
+import frappe
from frappe import _
+from frappe.model.document import Document
+
from erpnext.controllers.queries import item_query
+
class RestaurantOrderEntry(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
index e0c051b1ad7..ee8928b13a1 100644
--- a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
+++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class RestaurantOrderEntryItem(Document):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
index f96de44c3d6..f6d2a7c8cc4 100644
--- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
+++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
+
from datetime import timedelta
+
+from frappe.model.document import Document
from frappe.utils import get_datetime
+
class RestaurantReservation(Document):
def validate(self):
if not self.reservation_end_time:
diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
index 71681b2f183..885da724aa0 100644
--- a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
+++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestRestaurantReservation(unittest.TestCase):
pass
diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
index d5ea9d53981..0b5d6352711 100644
--- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
+++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py
@@ -3,10 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe, re
+
+import re
+
from frappe.model.document import Document
from frappe.model.naming import make_autoname
+
class RestaurantTable(Document):
def autoname(self):
prefix = re.sub('-+', '-', self.restaurant.replace(' ', '-'))
diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
index ffdb6f742a3..44059aee607 100644
--- a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
+++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
test_records = [
diff --git a/erpnext/selling/doctype/campaign/campaign.py b/erpnext/selling/doctype/campaign/campaign.py
index 10945428aee..09fea9a987c 100644
--- a/erpnext/selling/doctype/campaign/campaign.py
+++ b/erpnext/selling/doctype/campaign/campaign.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
from frappe.model.naming import set_name_by_naming_series
+
class Campaign(Document):
def autoname(self):
if frappe.defaults.get_global_default('campaign_naming_by') != 'Naming Series':
diff --git a/erpnext/selling/doctype/campaign/campaign_dashboard.py b/erpnext/selling/doctype/campaign/campaign_dashboard.py
index 3cef560c32f..990ebaae79c 100644
--- a/erpnext/selling/doctype/campaign/campaign_dashboard.py
+++ b/erpnext/selling/doctype/campaign/campaign_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'campaign_name',
diff --git a/erpnext/selling/doctype/campaign/test_campaign.py b/erpnext/selling/doctype/campaign/test_campaign.py
index 8c6617fe79a..bcb985b50f7 100644
--- a/erpnext/selling/doctype/campaign/test_campaign.py
+++ b/erpnext/selling/doctype/campaign/test_campaign.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Campaign')
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 27e9f08e8d6..2946cd9a172 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -2,20 +2,26 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
-from frappe.model.naming import set_name_by_naming_series
-from frappe import _, msgprint
+
+import frappe
import frappe.defaults
-from frappe.utils import flt, cint, cstr, today, get_formatted_email
+from frappe import _, msgprint
+from frappe.contacts.address_and_contact import (
+ delete_contact_and_address,
+ load_address_and_contact,
+)
from frappe.desk.reportview import build_match_conditions, get_filters_cond
-from erpnext.utilities.transaction_base import TransactionBase
-from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
-from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
-from frappe.model.rename_doc import update_linked_doctypes
from frappe.model.mapper import get_mapped_doc
+from frappe.model.naming import set_name_by_naming_series
+from frappe.model.rename_doc import update_linked_doctypes
+from frappe.utils import cint, cstr, flt, get_formatted_email, today
from frappe.utils.user import get_users_with_role
+from erpnext.accounts.party import get_dashboard_info, validate_party_accounts
+from erpnext.utilities.transaction_base import TransactionBase
+
class Customer(TransactionBase):
def get_feed(self):
@@ -286,30 +292,6 @@ class Customer(TransactionBase):
.format(frappe.bold(self.customer_name))
)
- def create_onboarding_docs(self, args):
- defaults = frappe.defaults.get_defaults()
- company = defaults.get('company') or \
- frappe.db.get_single_value('Global Defaults', 'default_company')
-
- for i in range(1, args.get('max_count')):
- customer = args.get('customer_name_' + str(i))
- if customer:
- try:
- doc = frappe.get_doc({
- 'doctype': self.doctype,
- 'customer_name': customer,
- 'customer_type': 'Company',
- 'customer_group': _('Commercial'),
- 'territory': defaults.get('country'),
- 'company': company
- }).insert()
-
- if args.get('customer_email_' + str(i)):
- create_contact(customer, self.doctype,
- doc.name, args.get("customer_email_" + str(i)))
- except frappe.NameError:
- pass
-
def create_contact(contact, party_type, party, email):
"""Create contact based on given contact name"""
contact = contact.split(' ')
diff --git a/erpnext/selling/doctype/customer/test_customer.js b/erpnext/selling/doctype/customer/test_customer.js
deleted file mode 100644
index 65b81af32c1..00000000000
--- a/erpnext/selling/doctype/customer/test_customer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Customer", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Customer
- () => frappe.tests.make('Customer', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 5b337313d3d..73daa85986b 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -3,13 +3,14 @@
from __future__ import unicode_literals
-import frappe
import unittest
-from erpnext.accounts.party import get_due_date
+import frappe
from frappe.test_runner import make_test_records
-from erpnext.exceptions import PartyFrozen, PartyDisabled
from frappe.utils import flt
+
+from erpnext.accounts.party import get_due_date
+from erpnext.exceptions import PartyDisabled, PartyFrozen
from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
from erpnext.tests.utils import create_test_contact_and_address
@@ -19,6 +20,7 @@ test_records = frappe.get_test_records('Customer')
from six import iteritems
+
class TestCustomer(unittest.TestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
@@ -253,10 +255,10 @@ class TestCustomer(unittest.TestCase):
return get_customer_outstanding('_Test Customer', '_Test Company')
def test_customer_credit_limit(self):
- from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
- from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
+ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
outstanding_amt = self.get_customer_outstanding_amount()
credit_limit = get_credit_limit('_Test Customer', '_Test Company')
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
index 60a4a9a5d25..53bcc1b102e 100644
--- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class CustomerCreditLimit(Document):
pass
diff --git a/erpnext/selling/doctype/industry_type/industry_type.py b/erpnext/selling/doctype/industry_type/industry_type.py
index 7a30d6524a0..6d413ece2e7 100644
--- a/erpnext/selling/doctype/industry_type/industry_type.py
+++ b/erpnext/selling/doctype/industry_type/industry_type.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class IndustryType(Document):
pass
diff --git a/erpnext/selling/doctype/industry_type/test_industry_type.py b/erpnext/selling/doctype/industry_type/test_industry_type.py
index ebc6366155e..d6cf79ba89b 100644
--- a/erpnext/selling/doctype/industry_type/test_industry_type.py
+++ b/erpnext/selling/doctype/industry_type/test_industry_type.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Industry Type')
diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py
index ffcbb2daf09..128a9415c87 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.py
+++ b/erpnext/selling/doctype/installation_note/installation_note.py
@@ -2,15 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
+from frappe import _
from frappe.utils import cstr, getdate
-from frappe import _
from erpnext.stock.utils import get_valid_serial_nos
-
from erpnext.utilities.transaction_base import TransactionBase
+
class InstallationNote(TransactionBase):
def __init__(self, *args, **kwargs):
super(InstallationNote, self).__init__(*args, **kwargs)
diff --git a/erpnext/selling/doctype/installation_note/test_installation_note.py b/erpnext/selling/doctype/installation_note/test_installation_note.py
index 553d070da0f..abfda9cd6b8 100644
--- a/erpnext/selling/doctype/installation_note/test_installation_note.py
+++ b/erpnext/selling/doctype/installation_note/test_installation_note.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Installation Note')
diff --git a/erpnext/selling/doctype/installation_note_item/installation_note_item.py b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
index 7e1205231bb..862c2a1bb51 100644
--- a/erpnext/selling/doctype/installation_note_item/installation_note_item.py
+++ b/erpnext/selling/doctype/installation_note_item/installation_note_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class InstallationNoteItem(Document):
pass
diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py
index ae3482f402b..4c73916f852 100644
--- a/erpnext/selling/doctype/product_bundle/product_bundle.py
+++ b/erpnext/selling/doctype/product_bundle/product_bundle.py
@@ -2,13 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
+from frappe import _
+from frappe.model.document import Document
from frappe.utils import get_link_to_form
-from frappe import _
-
-from frappe.model.document import Document
class ProductBundle(Document):
def autoname(self):
diff --git a/erpnext/selling/doctype/product_bundle/test_product_bundle.py b/erpnext/selling/doctype/product_bundle/test_product_bundle.py
index 7d1d372b111..13bd2a30923 100644
--- a/erpnext/selling/doctype/product_bundle/test_product_bundle.py
+++ b/erpnext/selling/doctype/product_bundle/test_product_bundle.py
@@ -3,8 +3,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Product Bundle')
def make_product_bundle(parent, items, qty=None):
diff --git a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
index 8721bfad866..5f71a27f369 100644
--- a/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
+++ b/erpnext/selling/doctype/product_bundle_item/product_bundle_item.py
@@ -3,8 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe.model.document import Document
+
class ProductBundleItem(Document):
pass
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 5a0d9c90655..474cf56fc1b 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -18,6 +18,8 @@ frappe.ui.form.on('Quotation', {
}
});
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
},
refresh: function(frm) {
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index 3eba62bc193..43a44900fcb 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -43,6 +43,8 @@
"ignore_pricing_rule",
"items_section",
"items",
+ "bundle_items_section",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"sec_break23",
@@ -926,6 +928,24 @@
"label": "Lost Reasons",
"options": "Quotation Lost Reason Detail",
"read_only": 1
+ },
+ {
+ "depends_on": "packed_items",
+ "fieldname": "packed_items",
+ "fieldtype": "Table",
+ "label": "Bundle Items",
+ "options": "Packed Item",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "packed_items",
+ "depends_on": "packed_items",
+ "fieldname": "bundle_items_section",
+ "fieldtype": "Section Break",
+ "label": "Bundle Items",
+ "options": "fa fa-suitcase",
+ "print_hide": 1
}
],
"icon": "fa fa-shopping-cart",
@@ -933,7 +953,7 @@
"is_submittable": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-10-30 13:58:59.212060",
+ "modified": "2021-08-27 20:10:07.864951",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index e4f8a475816..e9644cc722b 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.model.mapper import get_mapped_doc
-from frappe.utils import flt, nowdate, getdate
from frappe import _
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import flt, getdate, nowdate
from erpnext.controllers.selling_controller import SellingController
@@ -31,6 +32,9 @@ class Quotation(SellingController):
if self.items:
self.with_items = 1
+ from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+ make_packing_list(self)
+
def validate_valid_till(self):
if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
frappe.throw(_("Valid till date cannot be before transaction date"))
@@ -270,7 +274,7 @@ def _make_customer(source_name, ignore_permissions=False):
customer = frappe.get_doc(customer_doclist)
customer.flags.ignore_permissions = ignore_permissions
if quotation.get("party_name") == "Shopping Cart":
- customer.customer_group = frappe.db.get_value("Shopping Cart Settings", None,
+ customer.customer_group = frappe.db.get_value("E Commerce Settings", None,
"default_customer_group")
try:
diff --git a/erpnext/selling/doctype/quotation/quotation_dashboard.py b/erpnext/selling/doctype/quotation/quotation_dashboard.py
index d1bb788937b..9586cb10b59 100644
--- a/erpnext/selling/doctype/quotation/quotation_dashboard.py
+++ b/erpnext/selling/doctype/quotation/quotation_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'prevdoc_docname',
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 527a999aefa..a44089a9ce4 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import flt, add_days, nowdate, add_months, getdate
import unittest
+import frappe
+from frappe.utils import add_days, add_months, flt, getdate, nowdate
+
test_dependencies = ["Product Bundle"]
@@ -133,8 +134,10 @@ class TestQuotation(unittest.TestCase):
def test_create_quotation_with_margin(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
- from erpnext.selling.doctype.sales_order.sales_order \
- import make_delivery_note, make_sales_invoice
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_delivery_note,
+ make_sales_invoice,
+ )
rate_with_margin = flt((1500*18.75)/100 + 1500)
@@ -226,9 +229,87 @@ class TestQuotation(unittest.TestCase):
expired_quotation.reload()
self.assertEqual(expired_quotation.status, "Expired")
+ def test_product_bundle_mapping_on_creating_so(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.selling.doctype.quotation.quotation import make_sales_order
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=1, rate=100)
+ sales_order = make_sales_order(quotation.name)
+
+ quotation_item = [quotation.items[0].item_code, quotation.items[0].rate, quotation.items[0].qty, quotation.items[0].amount]
+ so_item = [sales_order.items[0].item_code, sales_order.items[0].rate, sales_order.items[0].qty, sales_order.items[0].amount]
+
+ self.assertEqual(quotation_item, so_item)
+
+ quotation_packed_items = [
+ [quotation.packed_items[0].parent_item, quotation.packed_items[0].item_code, quotation.packed_items[0].qty],
+ [quotation.packed_items[1].parent_item, quotation.packed_items[1].item_code, quotation.packed_items[1].qty]
+ ]
+ so_packed_items = [
+ [sales_order.packed_items[0].parent_item, sales_order.packed_items[0].item_code, sales_order.packed_items[0].qty],
+ [sales_order.packed_items[1].parent_item, sales_order.packed_items[1].item_code, sales_order.packed_items[1].qty]
+ ]
+
+ self.assertEqual(quotation_packed_items, so_packed_items)
+
+ def test_product_bundle_price_calculation_when_calculate_bundle_price_is_unchecked(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ bundle_item1 = make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ bundle_item2 = make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ bundle_item1.valuation_rate = 100
+ bundle_item1.save()
+
+ bundle_item2.valuation_rate = 200
+ bundle_item2.save()
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100)
+ self.assertEqual(quotation.items[0].amount, 200)
+
+ def test_product_bundle_price_calculation_when_calculate_bundle_price_is_checked(self):
+ from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+ from erpnext.stock.doctype.item.test_item import make_item
+
+ make_item("_Test Product Bundle", {"is_stock_item": 0})
+ make_item("_Test Bundle Item 1", {"is_stock_item": 1})
+ make_item("_Test Bundle Item 2", {"is_stock_item": 1})
+
+ make_product_bundle("_Test Product Bundle",
+ ["_Test Bundle Item 1", "_Test Bundle Item 2"])
+
+ enable_calculate_bundle_price()
+
+ quotation = make_quotation(item_code="_Test Product Bundle", qty=2, rate=100, do_not_submit=1)
+ quotation.packed_items[0].rate = 100
+ quotation.packed_items[1].rate = 200
+ quotation.save()
+
+ self.assertEqual(quotation.items[0].amount, 600)
+ self.assertEqual(quotation.items[0].rate, 300)
+
+ enable_calculate_bundle_price(enable=0)
test_records = frappe.get_test_records('Quotation')
+def enable_calculate_bundle_price(enable=1):
+ selling_settings = frappe.get_doc("Selling Settings")
+ selling_settings.editable_bundle_item_rates = enable
+ selling_settings.save()
+
def get_quotation_dict(party_name=None, item_code=None):
if not party_name:
party_name = '_Test Customer'
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 8b53902d32f..31a95896bc1 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -649,7 +649,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2021-02-23 01:13:54.670763",
+ "modified": "2021-07-15 12:40:51.074820",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.py b/erpnext/selling/doctype/quotation_item/quotation_item.py
index 7384871ed44..ea472497299 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.py
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QuotationItem(Document):
pass
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index e3b41e66fbc..1961371d0b8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -43,6 +43,9 @@ frappe.ui.form.on("Sales Order", {
}
}
});
+
+ frm.set_df_property('packed_items', 'cannot_add_rows', true);
+ frm.set_df_property('packed_items', 'cannot_delete_rows', true);
},
refresh: function(frm) {
if(frm.doc.docstatus === 1 && frm.doc.status !== 'Closed'
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 38ea5c81d49..85282ca1a07 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -55,6 +55,8 @@
"items_section",
"scan_barcode",
"items",
+ "packing_list",
+ "packed_items",
"pricing_rule_details",
"pricing_rules",
"section_break_31",
@@ -101,8 +103,6 @@
"in_words",
"advance_paid",
"disable_rounded_total",
- "packing_list",
- "packed_items",
"payment_schedule_section",
"payment_terms_template",
"payment_schedule",
@@ -1019,6 +1019,7 @@
{
"collapsible": 1,
"collapsible_depends_on": "packed_items",
+ "depends_on": "packed_items",
"fieldname": "packing_list",
"fieldtype": "Section Break",
"hide_days": 1,
@@ -1029,14 +1030,14 @@
"print_hide": 1
},
{
+ "depends_on": "packed_items",
"fieldname": "packed_items",
"fieldtype": "Table",
"hide_days": 1,
"hide_seconds": 1,
"label": "Packed Items",
"options": "Packed Item",
- "print_hide": 1,
- "read_only": 1
+ "print_hide": 1
},
{
"fieldname": "payment_schedule_section",
@@ -1511,7 +1512,7 @@
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2021-08-17 20:15:26.531553",
+ "modified": "2021-09-01 15:12:24.115483",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index bba54018aef..93676094218 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -2,24 +2,32 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import json
+
+import frappe
import frappe.utils
-from frappe.utils import cstr, flt, getdate, cint, nowdate, add_days, get_link_to_form, strip_html
from frappe import _
-from six import string_types
-from frappe.model.utils import get_fetch_values
-from frappe.model.mapper import get_mapped_doc
-from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
-from frappe.desk.notifications import clear_doctype_notifications
from frappe.contacts.doctype.address.address import get_company_address
+from frappe.desk.notifications import clear_doctype_notifications
+from frappe.model.mapper import get_mapped_doc
+from frappe.model.utils import get_fetch_values
+from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, getdate, nowdate, strip_html
+from six import string_types
+
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ unlink_inter_company_doc,
+ update_linked_doc,
+ validate_inter_company_party,
+)
from erpnext.controllers.selling_controller import SellingController
+from erpnext.manufacturing.doctype.production_plan.production_plan import (
+ get_items_for_material_requests,
+)
from erpnext.selling.doctype.customer.customer import check_credit_limit
-from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
-from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
-from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
- unlink_inter_company_doc
+from erpnext.stock.doctype.item.item import get_item_defaults
+from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -718,8 +726,7 @@ def make_maintenance_schedule(source_name, target_doc=None):
"doctype": "Maintenance Schedule Item",
"field_map": {
"parent": "sales_order"
- },
- "add_if_empty": True
+ }
}
}, target_doc)
@@ -745,8 +752,7 @@ def make_maintenance_visit(source_name, target_doc=None):
"field_map": {
"parent": "prevdoc_docname",
"parenttype": "prevdoc_doctype"
- },
- "add_if_empty": True
+ }
}
}, target_doc)
@@ -949,11 +955,52 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
"pricing_rules"
],
"postprocess": update_item,
- "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map
+ "condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map and not is_product_bundle(doc.item_code)
+ },
+ "Packed Item": {
+ "doctype": "Purchase Order Item",
+ "field_map": [
+ ["parent", "sales_order"],
+ ["uom", "uom"],
+ ["conversion_factor", "conversion_factor"],
+ ["parent_item", "product_bundle"],
+ ["rate", "rate"]
+ ],
+ "field_no_map": [
+ "price_list_rate",
+ "item_tax_template",
+ "discount_percentage",
+ "discount_amount",
+ "supplier",
+ "pricing_rules"
+ ],
}
}, target_doc, set_missing_values)
+
+ set_delivery_date(doc.items, source_name)
+
return doc
+def set_delivery_date(items, sales_order):
+ delivery_dates = frappe.get_all(
+ 'Sales Order Item',
+ filters = {
+ 'parent': sales_order
+ },
+ fields = ['delivery_date', 'item_code']
+ )
+
+ delivery_by_item = frappe._dict()
+ for date in delivery_dates:
+ delivery_by_item[date.item_code] = date.delivery_date
+
+ for item in items:
+ if item.product_bundle:
+ item.schedule_date = delivery_by_item[item.product_bundle]
+
+def is_product_bundle(item_code):
+ return frappe.db.exists('Product Bundle', item_code)
+
@frappe.whitelist()
def make_work_orders(items, sales_order, company, project=None):
'''Make Work Orders against the given Sales Order for the given `items`'''
diff --git a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
index 2a71c27009f..ee3c707b5b8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
+++ b/erpnext/selling/doctype/sales_order/sales_order_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'fieldname': 'sales_order',
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.js b/erpnext/selling/doctype/sales_order/test_sales_order.js
deleted file mode 100644
index 57ed19b6965..00000000000
--- a/erpnext/selling/doctype/sales_order/test_sales_order.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sales Order", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially('Sales Order', [
- // insert a new Sales Order
- () => frappe.tests.make([
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index d685fbff82b..62ea44df435 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1,21 +1,29 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import json
import unittest
+
import frappe
import frappe.permissions
-from frappe.utils import flt, add_days, nowdate, getdate
from frappe.core.doctype.user_permission.test_user_permission import create_user
-from erpnext.selling.doctype.sales_order.sales_order \
- import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired
-from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
-from erpnext.selling.doctype.sales_order.sales_order import make_work_orders
+from frappe.utils import add_days, flt, getdate, nowdate
+
from erpnext.controllers.accounts_controller import update_child_qty_rate
-from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+from erpnext.selling.doctype.sales_order.sales_order import (
+ WarehouseRequired,
+ make_delivery_note,
+ make_material_request,
+ make_raw_material_request,
+ make_sales_invoice,
+ make_work_orders,
+)
from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+
class TestSalesOrder(unittest.TestCase):
@@ -162,8 +170,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertEqual(so.get("items")[0].delivered_qty, 9)
# Make return deliver note, sales invoice and check quantity
- from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+ from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-3, do_not_submit=True)
dn1.items[0].against_sales_order = so.name
@@ -444,8 +452,8 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
def test_update_child_with_precision(self):
- from frappe.model.meta import get_field_precision
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+ from frappe.model.meta import get_field_precision
precision = get_field_precision(frappe.get_meta("Sales Order Item").get_field("rate"))
@@ -731,9 +739,11 @@ class TestSalesOrder(unittest.TestCase):
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
def test_drop_shipping(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
- update_status as so_update_status
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
+ from erpnext.selling.doctype.sales_order.sales_order import update_status as so_update_status
# make items
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -815,8 +825,10 @@ class TestSalesOrder(unittest.TestCase):
so.cancel()
def test_drop_shipping_partial_order(self):
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier, \
- update_status as so_update_status
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
+ from erpnext.selling.doctype.sales_order.sales_order import update_status as so_update_status
# make items
po_item1 = make_item("_Test Item for Drop Shipping 1", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -869,7 +881,9 @@ class TestSalesOrder(unittest.TestCase):
def test_drop_shipping_full_for_default_suppliers(self):
"""Test if multiple POs are generated in one go against different default suppliers."""
- from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_default_supplier
+ from erpnext.selling.doctype.sales_order.sales_order import (
+ make_purchase_order_for_default_supplier,
+ )
if not frappe.db.exists("Item", "_Test Item for Drop Shipping 1"):
make_item("_Test Item for Drop Shipping 1", {"is_stock_item": 1, "delivered_by_supplier": 1})
@@ -1043,8 +1057,7 @@ class TestSalesOrder(unittest.TestCase):
}]
})
so.submit()
- from erpnext.manufacturing.doctype.work_order.test_work_order import \
- make_wo_order_test_record
+ from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
work_order = make_wo_order_test_record(item=item.item_code,
qty=1, do_not_save=True)
work_order.fg_warehouse = "_Test Warehouse - _TC"
@@ -1052,8 +1065,9 @@ class TestSalesOrder(unittest.TestCase):
work_order.submit()
make_stock_entry(item_code=item.item_code, target="_Test Warehouse - _TC", qty=1)
item_serial_no = frappe.get_doc("Serial No", {"item_code": item.item_code})
- from erpnext.manufacturing.doctype.work_order.work_order import \
- make_stock_entry as make_production_stock_entry
+ from erpnext.manufacturing.doctype.work_order.work_order import (
+ make_stock_entry as make_production_stock_entry,
+ )
se = frappe.get_doc(make_production_stock_entry(work_order.name, "Manufacture", 1))
se.submit()
reserved_serial_no = se.get("items")[2].serial_no
@@ -1085,8 +1099,9 @@ class TestSalesOrder(unittest.TestCase):
si = make_sales_invoice(so.name)
si.update_stock = 0
si.submit()
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import \
- make_delivery_note as make_delivery_note_from_invoice
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
+ make_delivery_note as make_delivery_note_from_invoice,
+ )
dn = make_delivery_note_from_invoice(si.name)
dn.save()
dn.submit()
@@ -1123,6 +1138,7 @@ class TestSalesOrder(unittest.TestCase):
def test_cancel_sales_order_after_cancel_payment_entry(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+
# make a sales order
so = make_sales_order()
@@ -1232,7 +1248,9 @@ class TestSalesOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, so.cancel)
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
- from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template
+ from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
+ create_payment_terms_template,
+ )
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
automatically_fetch_payment_terms()
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.py b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
index 62afef3e170..772aa6c8ae5 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.py
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.py
@@ -2,10 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
+
class SalesOrderItem(Document):
pass
diff --git a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
index 68d289f0189..bdabef2fdbe 100644
--- a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
+++ b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class SalesPartnerType(Document):
pass
diff --git a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js
deleted file mode 100644
index 3ed7b46e1d9..00000000000
--- a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sales Partner Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sales Partner Type
- () => frappe.tests.make('Sales Partner Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
index fb8f8b0417a..895b0ecf00a 100644
--- a/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
+++ b/erpnext/selling/doctype/sales_partner_type/test_sales_partner_type.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestSalesPartnerType(unittest.TestCase):
pass
diff --git a/erpnext/selling/doctype/sales_team/sales_team.py b/erpnext/selling/doctype/sales_team/sales_team.py
index 28bea254d68..9b542c0eead 100644
--- a/erpnext/selling/doctype/sales_team/sales_team.py
+++ b/erpnext/selling/doctype/sales_team/sales_team.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class SalesTeam(Document):
pass
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index f01934b7e6b..28c7e5a4f53 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -6,24 +6,32 @@
"document_type": "Other",
"engine": "InnoDB",
"field_order": [
+ "customer_defaults_section",
"cust_master_name",
- "campaign_naming_by",
"customer_group",
+ "column_break_4",
"territory",
- "selling_price_list",
- "close_opportunity_after_days",
+ "crm_settings_section",
+ "campaign_naming_by",
"default_valid_till",
- "column_break_5",
+ "column_break_9",
+ "close_opportunity_after_days",
+ "item_price_settings_section",
+ "selling_price_list",
+ "maintain_same_rate_action",
+ "role_to_override_stop_action",
+ "column_break_15",
+ "maintain_same_sales_rate",
+ "editable_price_list_rate",
+ "validate_selling_price",
+ "editable_bundle_item_rates",
+ "transaction_settings_section",
"so_required",
"dn_required",
"sales_update_frequency",
- "maintain_same_sales_rate",
- "maintain_same_rate_action",
- "role_to_override_stop_action",
- "editable_price_list_rate",
+ "column_break_5",
"allow_multiple_items",
"allow_against_multiple_purchase_orders",
- "validate_selling_price",
"hide_tax_id"
],
"fields": [
@@ -75,10 +83,6 @@
"fieldtype": "Data",
"label": "Default Quotation Validity Days"
},
- {
- "fieldname": "column_break_5",
- "fieldtype": "Column Break"
- },
{
"fieldname": "so_required",
"fieldtype": "Select",
@@ -152,6 +156,48 @@
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "editable_bundle_item_rates",
+ "fieldtype": "Check",
+ "label": "Calculate Product Bundle Price based on Child Items' Rates"
+ },
+ {
+ "fieldname": "customer_defaults_section",
+ "fieldtype": "Section Break",
+ "label": "Customer Defaults"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "crm_settings_section",
+ "fieldtype": "Section Break",
+ "label": "CRM Settings"
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "item_price_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Item Price Settings"
+ },
+ {
+ "fieldname": "transaction_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Transaction Settings"
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-cog",
@@ -159,7 +205,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-04-04 20:18:12.814624",
+ "modified": "2021-09-06 22:05:06.139820",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py
index b219e7ecce0..5bed43e4609 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.py
@@ -4,17 +4,18 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-import frappe.defaults
-from frappe.utils import cint
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.model.document import Document
+from frappe.utils import cint
from frappe.utils.nestedset import get_root_of
-from frappe.model.document import Document
class SellingSettings(Document):
def on_update(self):
self.toggle_hide_tax_id()
+ self.toggle_editable_rate_for_bundle_items()
def validate(self):
for key in ["cust_master_name", "campaign_naming_by", "customer_group", "territory",
@@ -33,6 +34,11 @@ class SellingSettings(Document):
make_property_setter(doctype, "tax_id", "hidden", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "tax_id", "print_hide", self.hide_tax_id, "Check", validate_fields_for_doctype=False)
+ def toggle_editable_rate_for_bundle_items(self):
+ editable_bundle_item_rates = cint(self.editable_bundle_item_rates)
+
+ make_property_setter("Packed Item", "rate", "read_only", not(editable_bundle_item_rates), "Check", validate_fields_for_doctype=False)
+
def set_default_customer_group_and_territory(self):
if not self.customer_group:
self.customer_group = get_root_of('Customer Group')
diff --git a/erpnext/selling/doctype/selling_settings/test_selling_settings.py b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
index 961a54de0a8..572a110cc3e 100644
--- a/erpnext/selling/doctype/selling_settings/test_selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestSellingSettings(unittest.TestCase):
pass
diff --git a/erpnext/selling/doctype/sms_center/sms_center.py b/erpnext/selling/doctype/sms_center/sms_center.py
index 87846a84d30..45aee4ea6f0 100644
--- a/erpnext/selling/doctype/sms_center/sms_center.py
+++ b/erpnext/selling/doctype/sms_center/sms_center.py
@@ -2,14 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr
-from frappe import msgprint, _
-
-from frappe.model.document import Document
-
+from frappe import _, msgprint
from frappe.core.doctype.sms_settings.sms_settings import send_sms
+from frappe.model.document import Document
+from frappe.utils import cstr
+
class SMSCenter(Document):
@frappe.whitelist()
diff --git a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
deleted file mode 100644
index 92d00bcb380..00000000000
--- a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "add_more_button": 1,
- "app": "ERPNext",
- "creation": "2019-11-15 14:44:10.065014",
- "docstatus": 0,
- "doctype": "Onboarding Slide",
- "domains": [],
- "help_links": [
- {
- "label": "Learn More",
- "video_id": "zsrrVDk6VBs"
- }
- ],
- "idx": 0,
- "image_src": "",
- "is_completed": 0,
- "max_count": 3,
- "modified": "2019-12-09 17:54:01.686006",
- "modified_by": "Administrator",
- "name": "Add A Few Customers",
- "owner": "Administrator",
- "ref_doctype": "Customer",
- "slide_desc": "",
- "slide_fields": [
- {
- "align": "",
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "label": "Customer Name",
- "placeholder": "",
- "reqd": 1
- },
- {
- "align": "",
- "fieldtype": "Column Break",
- "reqd": 0
- },
- {
- "align": "",
- "fieldname": "customer_email",
- "fieldtype": "Data",
- "label": "Email ID",
- "reqd": 1
- }
- ],
- "slide_order": 40,
- "slide_title": "Add A Few Customers",
- "slide_type": "Create"
-}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 03c46bb2ae0..b4338c920a9 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -2,11 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, json
+
+import json
+
+import frappe
from frappe.utils.nestedset import get_root_of
-from frappe.utils import cint
-from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
+
from erpnext.accounts.doctype.pos_invoice.pos_invoice import get_stock_availability
+from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
+
def search_by_term(search_term, warehouse, price_list):
result = search_for_serial_or_batch_or_barcode_number(search_term) or {}
@@ -209,7 +213,6 @@ def check_opening_entry(user):
@frappe.whitelist()
def create_opening_voucher(pos_profile, company, balance_details):
- import json
balance_details = json.loads(balance_details)
new_pos_opening = frappe.get_doc({
diff --git a/erpnext/selling/page/point_of_sale/pos_payment.js b/erpnext/selling/page/point_of_sale/pos_payment.js
index 63306adc6fa..7ddbf45fdb8 100644
--- a/erpnext/selling/page/point_of_sale/pos_payment.js
+++ b/erpnext/selling/page/point_of_sale/pos_payment.js
@@ -253,41 +253,6 @@ erpnext.PointOfSale.Payment = class {
}
}
- setup_listener_for_payments() {
- frappe.realtime.on("process_phone_payment", (data) => {
- const doc = this.events.get_frm().doc;
- const { response, amount, success, failure_message } = data;
- let message, title;
-
- if (success) {
- title = __("Payment Received");
- if (amount >= doc.grand_total) {
- frappe.dom.unfreeze();
- message = __("Payment of {0} received successfully.", [format_currency(amount, doc.currency, 0)]);
- this.events.submit_invoice();
- cur_frm.reload_doc();
-
- } else {
- message = __("Payment of {0} received successfully. Waiting for other requests to complete...", [format_currency(amount, doc.currency, 0)]);
- }
- } else if (failure_message) {
- message = failure_message;
- title = __("Payment Failed");
- }
-
- frappe.msgprint({ "message": message, "title": title });
- });
- }
-
- auto_set_remaining_amount() {
- const doc = this.events.get_frm().doc;
- const remaining_amount = doc.grand_total - doc.paid_amount;
- const current_value = this.selected_mode ? this.selected_mode.get_value() : undefined;
- if (!current_value && remaining_amount > 0 && this.selected_mode) {
- this.selected_mode.set_value(remaining_amount);
- }
- }
-
attach_shortcuts() {
const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`);
@@ -332,6 +297,7 @@ erpnext.PointOfSale.Payment = class {
this.render_payment_mode_dom();
this.make_invoice_fields_control();
this.update_totals_section();
+ this.focus_on_default_mop();
}
edit_cart() {
@@ -413,17 +379,24 @@ erpnext.PointOfSale.Payment = class {
});
this[`${mode}_control`].toggle_label(false);
this[`${mode}_control`].set_value(p.amount);
+ });
+ this.render_loyalty_points_payment_mode();
+
+ this.attach_cash_shortcuts(doc);
+ }
+
+ focus_on_default_mop() {
+ const doc = this.events.get_frm().doc;
+ const payments = doc.payments;
+ payments.forEach(p => {
+ const mode = p.mode_of_payment.replace(/ +/g, "_").toLowerCase();
if (p.default) {
setTimeout(() => {
this.$payment_modes.find(`.${mode}.mode-of-payment-control`).parent().click();
}, 500);
}
});
-
- this.render_loyalty_points_payment_mode();
-
- this.attach_cash_shortcuts(doc);
}
attach_cash_shortcuts(doc) {
diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py
index 78aaa49a668..043a3e7f0fa 100644
--- a/erpnext/selling/page/sales_funnel/sales_funnel.py
+++ b/erpnext/selling/page/sales_funnel/sales_funnel.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
-from erpnext.accounts.report.utils import convert
+import frappe
import pandas as pd
+from frappe import _
+
+from erpnext.accounts.report.utils import convert
+
def validate_filters(from_date, to_date, company):
if from_date and to_date and (from_date >= to_date):
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
index f295333322c..fea19f9f16d 100644
--- a/erpnext/selling/report/address_and_contacts/address_and_contacts.py
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
@@ -2,10 +2,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from six.moves import range
-from six import iteritems
-import frappe
+import frappe
+from six import iteritems
+from six.moves import range
field_map = {
"Contact": [ "first_name", "last_name", "phone", "mobile_no", "email_id", "is_primary_contact" ],
diff --git a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
index 5523bad5715..c7040bef708 100644
--- a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
+++ b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils import flt
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
index f15f63d7bb7..a29b5c8a627 100644
--- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
+++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import calendar
+
import frappe
from frappe import _
from frappe.utils import cint, cstr, getdate
+
def execute(filters=None):
common_columns = [
{
diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
index 6fb7666c2ce..ed2fbfd595c 100644
--- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
+++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
-from erpnext.selling.doctype.customer.customer import get_customer_outstanding, get_credit_limit
+
+from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
index eb9273a5626..535d551cfab 100644
--- a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
+++ b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py
@@ -4,10 +4,11 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
+
from erpnext import get_default_company
from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_price_list_rate_for
-from frappe import _
def execute(filters=None):
diff --git a/erpnext/selling/report/inactive_customers/inactive_customers.py b/erpnext/selling/report/inactive_customers/inactive_customers.py
index e7aff36e828..c79efe24b78 100644
--- a/erpnext/selling/report/inactive_customers/inactive_customers.py
+++ b/erpnext/selling/report/inactive_customers/inactive_customers.py
@@ -2,9 +2,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cint
from frappe import _
+from frappe.utils import cint
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
index 1700fc7bdd5..539631240e1 100644
--- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
@@ -2,11 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils.nestedset import get_descendants_of
+
def execute(filters=None):
filters = frappe._dict(filters or {})
if filters.from_date > filters.to_date:
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
index e89c45182fd..f241a3e13d9 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
columns = get_columns()
data = get_data()
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
index f2518f09f8e..95e332ac537 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
@@ -2,12 +2,16 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import unittest
-from frappe.utils import nowdate, add_months
-from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request\
- import execute
+
+from frappe.utils import add_months, nowdate
+
from erpnext.selling.doctype.sales_order.sales_order import make_material_request
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import (
+ execute,
+)
class TestPendingSOItemsForPurchaseRequest(unittest.TestCase):
diff --git a/erpnext/selling/report/quotation_trends/quotation_trends.py b/erpnext/selling/report/quotation_trends/quotation_trends.py
index 968e2ff26f7..d2ee9a8b742 100644
--- a/erpnext/selling/report/quotation_trends/quotation_trends.py
+++ b/erpnext/selling/report/quotation_trends/quotation_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns, get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index d036a1cb095..56bcb3180a3 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -2,12 +2,15 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _, scrub
-from frappe.utils import getdate, flt, add_to_date, add_days
+from frappe.utils import add_days, add_to_date, flt, getdate
from six import iteritems
+
from erpnext.accounts.utils import get_fiscal_year
+
def execute(filters=None):
return Analytics(filters).run()
@@ -293,7 +296,7 @@ class Analytics(object):
return period
def get_period_date_ranges(self):
- from dateutil.relativedelta import relativedelta, MO
+ from dateutil.relativedelta import MO, relativedelta
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
increment = {
diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py
index 4d81a1e4dda..a1800993f4f 100644
--- a/erpnext/selling/report/sales_analytics/test_analytics.py
+++ b/erpnext/selling/report/sales_analytics/test_analytics.py
@@ -2,11 +2,14 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
-import frappe.defaults
+
import unittest
-from erpnext.selling.report.sales_analytics.sales_analytics import execute
+
+import frappe
+
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.selling.report.sales_analytics.sales_analytics import execute
+
class TestAnalytics(unittest.TestCase):
def test_sales_analytics(self):
diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
index 00dcd69c6e6..805c3d804fa 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+
+import frappe
from frappe import _
-from frappe.utils import flt, date_diff, getdate
+from frappe.utils import date_diff, flt, getdate
+
def execute(filters=None):
if not filters:
diff --git a/erpnext/selling/report/sales_order_trends/sales_order_trends.py b/erpnext/selling/report/sales_order_trends/sales_order_trends.py
index de7d3f2f778..89daf447781 100644
--- a/erpnext/selling/report/sales_order_trends/sales_order_trends.py
+++ b/erpnext/selling/report/sales_order_trends/sales_order_trends.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _
-from erpnext.controllers.trends import get_columns,get_data
+
+from erpnext.controllers.trends import get_columns, get_data
+
def execute(filters=None):
if not filters: filters ={}
diff --git a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
index 2c49d51a920..a84dec032e5 100644
--- a/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
+++ b/erpnext/selling/report/sales_partner_commission_summary/sales_partner_commission_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
index 89cfa16abe0..d4f49c71464 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/item_group_wise_sales_target_variance.py
@@ -2,12 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt
-from erpnext.accounts.utils import get_fiscal_year
+
+from erpnext.accounts.doctype.monthly_distribution.monthly_distribution import (
+ get_periodwise_distribution_data,
+)
from erpnext.accounts.report.financial_statements import get_period_list
-from erpnext.accounts.doctype.monthly_distribution.monthly_distribution import get_periodwise_distribution_data
+from erpnext.accounts.utils import get_fiscal_year
+
def get_data_column(filters, partner_doctype):
data = []
diff --git a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
index 87ed5a8ea21..de21c4ad02d 100644
--- a/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_partner_target_variance_based_on_item_group/sales_partner_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
index f07293d8ec2..39ec072f6ba 100644
--- a/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
+++ b/erpnext/selling/report/sales_partner_transaction_summary/sales_partner_transaction_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
index 9917d72af86..13245b789ef 100644
--- a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
+++ b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.py
@@ -2,9 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
def execute(filters=None):
diff --git a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
index ea9bbab0c72..83a1c2ce75c 100644
--- a/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/sales_person_target_variance_based_on_item_group/sales_person_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
index 41c7f765175..9dc2923b0a2 100644
--- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
+++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import msgprint, _
-from frappe.utils import flt
+from frappe import _, msgprint
+
from erpnext import get_company_currency
+
def execute(filters=None):
if not filters: filters = {}
diff --git a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
index b1d89cc3fb8..b340124a040 100644
--- a/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
+++ b/erpnext/selling/report/territory_target_variance_based_on_item_group/territory_target_variance_based_on_item_group.py
@@ -2,8 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import get_data_column
+
+from erpnext.selling.report.sales_partner_target_variance_based_on_item_group.item_group_wise_sales_target_variance import (
+ get_data_column,
+)
+
def execute(filters=None):
data = []
diff --git a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
index e8835001707..c334381b430 100644
--- a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
+++ b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
@@ -2,10 +2,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
-from erpnext import get_default_currency
from frappe import _
+from erpnext import get_default_currency
+
+
def execute(filters=None):
filters = frappe._dict(filters)
columns = get_columns()
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 26ac630a32b..091c22271e6 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -90,10 +90,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.frm.toggle_display("customer_name",
(this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer));
- if(this.frm.fields_dict.packed_items) {
- var packing_list_exists = (this.frm.doc.packed_items || []).length;
- this.frm.toggle_display("packing_list", packing_list_exists ? true : false);
- }
+
this.toggle_editable_price_list_rate();
},
diff --git a/erpnext/setup/default_energy_point_rules.py b/erpnext/setup/default_energy_point_rules.py
index 8dbccc497b7..c41d000215b 100644
--- a/erpnext/setup/default_energy_point_rules.py
+++ b/erpnext/setup/default_energy_point_rules.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
doctype_rule_map = {
diff --git a/erpnext/setup/default_success_action.py b/erpnext/setup/default_success_action.py
index 827839f8b75..be072fc47f3 100644
--- a/erpnext/setup/default_success_action.py
+++ b/erpnext/setup/default_success_action.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+
from frappe import _
doctype_list = [
diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py
index fec5c7ca95d..332d7f438a7 100644
--- a/erpnext/setup/doctype/authorization_control/authorization_control.py
+++ b/erpnext/setup/doctype/authorization_control/authorization_control.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe.utils import cstr, flt, has_common, comma_or
-from frappe import session, _
+from frappe import _, session
+from frappe.utils import comma_or, cstr, flt, has_common
+
from erpnext.utilities.transaction_base import TransactionBase
+
class AuthorizationControl(TransactionBase):
def get_appr_user_role(self, det, doctype_name, total, based_on, condition, item, company):
amt_list, appr_users, appr_roles = [], [], []
diff --git a/erpnext/setup/doctype/authorization_rule/authorization_rule.py b/erpnext/setup/doctype/authorization_rule/authorization_rule.py
index eb8e6ebe78c..ab0f4201219 100644
--- a/erpnext/setup/doctype/authorization_rule/authorization_rule.py
+++ b/erpnext/setup/doctype/authorization_rule/authorization_rule.py
@@ -2,12 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr, flt
-from frappe import _, msgprint
-
+from frappe import _
from frappe.model.document import Document
+from frappe.utils import cstr, flt
+
class AuthorizationRule(Document):
def check_duplicate_entry(self):
diff --git a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
index 332f1039921..8a0f6649078 100644
--- a/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
+++ b/erpnext/setup/doctype/authorization_rule/test_authorization_rule.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Authorization Rule')
diff --git a/erpnext/setup/doctype/brand/brand.json b/erpnext/setup/doctype/brand/brand.json
index a8f0674b1f8..45b4db81f1f 100644
--- a/erpnext/setup/doctype/brand/brand.json
+++ b/erpnext/setup/doctype/brand/brand.json
@@ -1,270 +1,111 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:brand",
- "beta": 0,
- "creation": "2013-02-22 01:27:54",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:brand",
+ "creation": "2013-02-22 01:27:54",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "brand",
+ "image",
+ "description",
+ "defaults",
+ "brand_defaults"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 1,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "brand",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Brand Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "brand",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_in_quick_entry": 1,
+ "fieldname": "brand",
+ "fieldtype": "Data",
+ "label": "Brand Name",
+ "oldfieldname": "brand",
+ "oldfieldtype": "Data",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "defaults",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Defaults",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "defaults",
+ "fieldtype": "Section Break",
+ "label": "Defaults"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "brand_defaults",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Brand Defaults",
- "length": 0,
- "no_copy": 0,
- "options": "Item Default",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "brand_defaults",
+ "fieldtype": "Table",
+ "label": "Brand Defaults",
+ "options": "Item Default"
+ },
+ {
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Image"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-certificate",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-10-23 23:18:06.067612",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Brand",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-certificate",
+ "idx": 1,
+ "image_field": "image",
+ "links": [],
+ "modified": "2021-03-01 15:57:30.005783",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Brand",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Item Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Item Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase User"
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User"
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "quick_entry": 1,
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC"
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/brand/brand.py b/erpnext/setup/doctype/brand/brand.py
index a8d1cf8ff2d..4cfb018c865 100644
--- a/erpnext/setup/doctype/brand/brand.py
+++ b/erpnext/setup/doctype/brand/brand.py
@@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+import frappe
from frappe.model.document import Document
+
class Brand(Document):
pass
diff --git a/erpnext/setup/doctype/brand/test_brand.py b/erpnext/setup/doctype/brand/test_brand.py
index 25ed86ef1dd..16873c9fc92 100644
--- a/erpnext/setup/doctype/brand/test_brand.py
+++ b/erpnext/setup/doctype/brand/test_brand.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Brand')
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 45d5ce0c1c7..f9f70264f6d 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -2,23 +2,24 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, os, json
-from frappe import _
-from frappe.utils import get_timestamp
-from frappe.utils import cint, today, formatdate
-import frappe.defaults
-from frappe.cache_manager import clear_defaults_cache
-
-from frappe.model.document import Document
-from frappe.contacts.address_and_contact import load_address_and_contact
-from frappe.utils.nestedset import NestedSet
-
-from past.builtins import cmp
import functools
+import json
+import os
+
+import frappe
+import frappe.defaults
+from frappe import _
+from frappe.cache_manager import clear_defaults_cache
+from frappe.contacts.address_and_contact import load_address_and_contact
+from frappe.utils import cint, formatdate, get_timestamp, today
+from frappe.utils.nestedset import NestedSet
+from past.builtins import cmp
+
from erpnext.accounts.doctype.account.account import get_account_currency
from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges
+
class Company(NestedSet):
nsm_parent_field = 'parent_company'
@@ -479,8 +480,9 @@ def update_company_current_month_sales(company):
def update_company_monthly_sales(company):
'''Cache past year monthly sales of every company based on sales invoices'''
- from frappe.utils.goal import get_monthly_results
import json
+
+ from frappe.utils.goal import get_monthly_results
filter_str = "company = {0} and status != 'Draft' and docstatus=1".format(frappe.db.escape(company))
month_to_value_dict = get_monthly_results("Sales Invoice", "base_grand_total",
"posting_date", filter_str, "sum")
diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py
index 2d760284e5a..3afea098a0f 100644
--- a/erpnext/setup/doctype/company/company_dashboard.py
+++ b/erpnext/setup/doctype/company/company_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'graph': True,
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 1b7fd4fd5c8..abc4689a20e 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -2,12 +2,16 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-import unittest
import json
+import unittest
+
+import frappe
from frappe import _
from frappe.utils import random_string
-from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import get_charts_for_country
+
+from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import (
+ get_charts_for_country,
+)
test_ignore = ["Account", "Cost Center", "Payment Terms Template", "Salary Component", "Warehouse"]
test_dependencies = ["Fiscal Year"]
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.py b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
index 6480f60f59c..0b86e293778 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
@@ -4,10 +4,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
from frappe import _, throw
from frappe.model.document import Document
-from frappe.utils import get_datetime_str, formatdate, nowdate, cint
+from frappe.utils import cint, formatdate, get_datetime_str, nowdate
+
class CurrencyExchange(Document):
def autoname(self):
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js
deleted file mode 100644
index 19fde2e1481..00000000000
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Currency Exchange", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Currency Exchange
- () => frappe.tests.make('Currency Exchange', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
index 4ff2dd7e0e9..1e159c96c59 100644
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
@@ -1,10 +1,13 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, unittest
-from frappe.utils import flt
+
+import unittest
+
+import frappe
+from frappe.utils import cint, flt
+
from erpnext.setup.utils import get_exchange_rate
-from frappe.utils import cint
test_records = frappe.get_test_records('Currency Exchange')
diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py
index c06669b16b4..6e72810c561 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.py
+++ b/erpnext/setup/doctype/customer_group/customer_group.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-
-
from frappe.utils.nestedset import NestedSet, get_root_of
+
+
class CustomerGroup(NestedSet):
nsm_parent_field = 'parent_customer_group'
def validate(self):
diff --git a/erpnext/setup/doctype/customer_group/test_customer_group.py b/erpnext/setup/doctype/customer_group/test_customer_group.py
index ec90b376cdc..e04b79b8f39 100644
--- a/erpnext/setup/doctype/customer_group/test_customer_group.py
+++ b/erpnext/setup/doctype/customer_group/test_customer_group.py
@@ -7,4 +7,5 @@ test_ignore = ["Price List"]
import frappe
+
test_records = frappe.get_test_records('Customer Group')
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 6fbd4cd78cf..4e9a8ccad87 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -2,19 +2,34 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
-from frappe.utils import (fmt_money, formatdate, format_time, now_datetime,
- get_url_to_form, get_url_to_list, flt, get_link_to_report, add_to_date, today)
+
from datetime import timedelta
-from dateutil.relativedelta import relativedelta
-from frappe.core.doctype.user.user import STANDARD_USERS
+
+import frappe
import frappe.desk.notifications
+from dateutil.relativedelta import relativedelta
+from frappe import _
+from frappe.core.doctype.user.user import STANDARD_USERS
+from frappe.utils import (
+ add_to_date,
+ flt,
+ fmt_money,
+ format_time,
+ formatdate,
+ get_link_to_report,
+ get_url_to_form,
+ get_url_to_list,
+ now_datetime,
+ today,
+)
+
from erpnext.accounts.utils import get_balance_on, get_count_on, get_fiscal_year
user_specific_content = ["calendar_events", "todo_list"]
from frappe.model.document import Document
+
+
class EmailDigest(Document):
def __init__(self, *args, **kwargs):
super(EmailDigest, self).__init__(*args, **kwargs)
@@ -60,9 +75,6 @@ class EmailDigest(Document):
reference_name = self.name,
unsubscribe_message = _("Unsubscribe from this Email Digest"))
- frappe.set_user(original_user)
- frappe.set_user_lang(original_user)
-
def get_msg_html(self):
"""Build email digest content"""
frappe.flags.ignore_account_permission = True
diff --git a/erpnext/setup/doctype/email_digest/quotes.py b/erpnext/setup/doctype/email_digest/quotes.py
index 5451ee1daff..c77fe824ac9 100644
--- a/erpnext/setup/doctype/email_digest/quotes.py
+++ b/erpnext/setup/doctype/email_digest/quotes.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+
import random
+
def get_random_quote():
quotes = [
("Start by doing what's necessary; then do what's possible; and suddenly you are doing the impossible.", "Francis of Assisi"),
diff --git a/erpnext/setup/doctype/email_digest/test_email_digest.py b/erpnext/setup/doctype/email_digest/test_email_digest.py
index afe693afd2f..b3d0ce325b8 100644
--- a/erpnext/setup/doctype/email_digest/test_email_digest.py
+++ b/erpnext/setup/doctype/email_digest/test_email_digest.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Email Digest')
diff --git a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
index 968c51c345b..5c8d695b6e5 100644
--- a/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
+++ b/erpnext/setup/doctype/email_digest_recipient/email_digest_recipient.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class EmailDigestRecipient(Document):
pass
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index a0ba1efb5b4..66d3b9ee480 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -2,11 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
"""Global Defaults"""
import frappe
import frappe.defaults
-from frappe.utils import cint
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
+from frappe.utils import cint
keydict = {
# "key in defaults": "key in Global Defaults"
@@ -22,6 +23,7 @@ keydict = {
from frappe.model.document import Document
+
class GlobalDefaults(Document):
def on_update(self):
diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.js b/erpnext/setup/doctype/global_defaults/test_global_defaults.js
deleted file mode 100644
index 33634eb0f88..00000000000
--- a/erpnext/setup/doctype/global_defaults/test_global_defaults.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Global Defaults", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Global Defaults
- () => frappe.tests.make('Global Defaults', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/global_defaults/test_global_defaults.py b/erpnext/setup/doctype/global_defaults/test_global_defaults.py
index 0495af7b414..70a7c08c111 100644
--- a/erpnext/setup/doctype/global_defaults/test_global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/test_global_defaults.py
@@ -3,8 +3,8 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
class TestGlobalDefaults(unittest.TestCase):
pass
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 5fcad00af16..0943b22c028 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -2,19 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+
import copy
+
+import frappe
from frappe import _
-from frappe.utils import nowdate, cint, cstr
+from frappe.utils import cint
from frappe.utils.nestedset import NestedSet
-from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache
-from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
-from erpnext.shopping_cart.product_info import set_product_info_for_website
-from erpnext.utilities.product import get_qty_in_stock
+from frappe.website.website_generator import WebsiteGenerator
from six.moves.urllib.parse import quote
-from erpnext.shopping_cart.product_query import ProductQuery
-from erpnext.shopping_cart.filters import ProductFiltersBuilder
+
+from erpnext.e_commerce.product_data_engine.filters import ProductFiltersBuilder
+
class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group'
@@ -69,34 +69,15 @@ class ItemGroup(NestedSet, WebsiteGenerator):
frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name), frappe.NameError)
def get_context(self, context):
- context.show_search=True
- context.page_length = cint(frappe.db.get_single_value('Products Settings', 'products_per_page')) or 6
+ context.show_search = True
+ context.body_class = "product-page"
+ context.page_length = cint(frappe.db.get_single_value('E Commerce Settings', 'products_per_page')) or 6
context.search_link = '/product_search'
- if frappe.form_dict:
- search = frappe.form_dict.search
- field_filters = frappe.parse_json(frappe.form_dict.field_filters)
- attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
- start = frappe.parse_json(frappe.form_dict.start)
- else:
- search = None
- attribute_filters = None
- field_filters = {}
- start = 0
-
- if not field_filters:
- field_filters = {}
-
- # Ensure the query remains within current item group & sub group
- field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
-
- engine = ProductQuery()
- context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
-
filter_engine = ProductFiltersBuilder(self.name)
context.field_filters = filter_engine.get_field_filters()
- context.attribute_filters = filter_engine.get_attribute_fitlers()
+ context.attribute_filters = filter_engine.get_attribute_filters()
context.update({
"parents": get_parent_item_groups(self.parent_item_group),
@@ -116,106 +97,40 @@ class ItemGroup(NestedSet, WebsiteGenerator):
values[f"slide_{index + 1}_image"] = slide.image
values[f"slide_{index + 1}_title"] = slide.heading
values[f"slide_{index + 1}_subtitle"] = slide.description
- values[f"slide_{index + 1}_theme"] = slide.theme or "Light"
- values[f"slide_{index + 1}_content_align"] = slide.content_align or "Centre"
- values[f"slide_{index + 1}_primary_action_label"] = slide.label
+ values[f"slide_{index + 1}_theme"] = slide.get("theme") or "Light"
+ values[f"slide_{index + 1}_content_align"] = slide.get("content_align") or "Centre"
values[f"slide_{index + 1}_primary_action"] = slide.url
context.slideshow = values
- context.breadcrumbs = 0
+ context.no_breadcrumbs = False
context.title = self.website_title or self.name
+ context.name = self.name
+ context.item_group_name = self.item_group_name
return context
def delete_child_item_groups_key(self):
frappe.cache().hdel("child_item_groups", self.name)
-@frappe.whitelist(allow_guest=True)
-def get_product_list_for_group(product_group=None, start=0, limit=10, search=None):
- if product_group:
- item_group = frappe.get_cached_doc('Item Group', product_group)
- if item_group.is_group:
- # return child item groups if the type is of "Is Group"
- return get_child_groups_for_list_in_html(item_group, start, limit, search)
+def get_child_groups_for_website(item_group_name, immediate=False):
+ """Returns child item groups *excluding* passed group."""
+ item_group = frappe.get_cached_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
+ filters = {
+ "lft": [">", item_group.lft],
+ "rgt": ["<", item_group.rgt],
+ "show_in_website": 1
+ }
- child_groups = ", ".join(frappe.db.escape(i[0]) for i in get_child_groups(product_group))
+ if immediate:
+ filters["parent_item_group"] = item_group_name
- # base query
- query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group,
- I.description, I.web_long_description as website_description, I.is_stock_item,
- case when (S.actual_qty - S.reserved_qty) > 0 then 1 else 0 end as in_stock, I.website_warehouse,
- I.has_batch_no
- from `tabItem` I
- left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse
- where I.show_in_website = 1
- and I.disabled = 0
- and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)
- and (I.variant_of = '' or I.variant_of is null)
- and (I.item_group in ({child_groups})
- or I.name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups})))
- """.format(child_groups=child_groups)
- # search term condition
- if search:
- query += """ and (I.web_long_description like %(search)s
- or I.item_name like %(search)s
- or I.name like %(search)s)"""
- search = "%" + cstr(search) + "%"
-
- query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
-
- data = frappe.db.sql(query, {"product_group": product_group,"search": search, "today": nowdate()}, as_dict=1)
- data = adjust_qty_for_expired_items(data)
-
- if cint(frappe.db.get_single_value("Shopping Cart Settings", "enabled")):
- for item in data:
- set_product_info_for_website(item)
-
- return data
-
-def get_child_groups_for_list_in_html(item_group, start, limit, search):
- search_filters = None
- if search_filters:
- search_filters = [
- dict(name = ('like', '%{}%'.format(search))),
- dict(description = ('like', '%{}%'.format(search)))
- ]
- data = frappe.db.get_all('Item Group',
- fields = ['name', 'route', 'description', 'image'],
- filters = dict(
- show_in_website = 1,
- parent_item_group = item_group.name,
- lft = ('>', item_group.lft),
- rgt = ('<', item_group.rgt),
- ),
- or_filters = search_filters,
- order_by = 'weightage desc, name asc',
- start = start,
- limit = limit
+ return frappe.get_all(
+ "Item Group",
+ filters=filters,
+ fields=["name", "route"]
)
- return data
-
-def adjust_qty_for_expired_items(data):
- adjusted_data = []
-
- for item in data:
- if item.get('has_batch_no') and item.get('website_warehouse'):
- stock_qty_dict = get_qty_in_stock(
- item.get('name'), 'website_warehouse', item.get('website_warehouse'))
- qty = stock_qty_dict.stock_qty[0][0] if stock_qty_dict.stock_qty else 0
- item['in_stock'] = 1 if qty else 0
- adjusted_data.append(item)
-
- return adjusted_data
-
-
-def get_child_groups(item_group_name):
- item_group = frappe.get_doc("Item Group", item_group_name)
- return frappe.db.sql("""select name
- from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
- and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
-
def get_child_item_groups(item_group_name):
item_group = frappe.get_cached_value("Item Group",
item_group_name, ["lft", "rgt"], as_dict=1)
@@ -231,31 +146,33 @@ def get_item_for_list_in_html(context):
if (context.get("website_image") or "").startswith("files/"):
context["website_image"] = "/" + quote(context["website_image"])
- context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings',
+ context["show_availability_status"] = cint(frappe.db.get_single_value('E Commerce Settings',
'show_availability_status'))
products_template = 'templates/includes/products_as_list.html'
return frappe.get_template(products_template).render(context)
-def get_group_item_count(item_group):
- child_groups = ", ".join('"' + i[0] + '"' for i in get_child_groups(item_group))
- return frappe.db.sql("""select count(*) from `tabItem`
- where docstatus = 0 and show_in_website = 1
- and (item_group in (%s)
- or name in (select parent from `tabWebsite Item Group`
- where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
+def get_parent_item_groups(item_group_name, from_item=False):
+ base_nav_page = {"name": _("Shop by Category"), "route":"/shop-by-category"}
+
+ if from_item and frappe.request.environ.get("HTTP_REFERER"):
+ # base page after 'Home' will vary on Item page
+ last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
+ if last_page and last_page in ("shop-by-category", "all-products"):
+ base_nav_page_title = " ".join(last_page.split("-")).title()
+ base_nav_page = {"name": _(base_nav_page_title), "route":"/"+last_page}
-def get_parent_item_groups(item_group_name):
base_parents = [
- {"name": frappe._("Home"), "route":"/"},
- {"name": frappe._("All Products"), "route":"/all-products"},
+ {"name": _("Home"), "route":"/"},
+ base_nav_page,
]
+
if not item_group_name:
return base_parents
- item_group = frappe.get_doc("Item Group", item_group_name)
+ item_group = frappe.db.get_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
where lft <= %s and rgt >= %s
and show_in_website=1
diff --git a/erpnext/setup/doctype/item_group/test_item_group.js b/erpnext/setup/doctype/item_group/test_item_group.js
deleted file mode 100644
index ea322e23d65..00000000000
--- a/erpnext/setup/doctype/item_group/test_item_group.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Item Group", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Item Group
- () => frappe.tests.make('Item Group', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/item_group/test_item_group.py b/erpnext/setup/doctype/item_group/test_item_group.py
index 745b13a5bed..a816f391c62 100644
--- a/erpnext/setup/doctype/item_group/test_item_group.py
+++ b/erpnext/setup/doctype/item_group/test_item_group.py
@@ -2,10 +2,18 @@
# License: GNU General Public License v3. See license.txt
from __future__ import print_function, unicode_literals
+
import unittest
+
import frappe
-from frappe.utils.nestedset import NestedSetRecursionError, NestedSetMultipleRootsError, \
- NestedSetChildExistsError, NestedSetInvalidMergeError, rebuild_tree, get_ancestors_of
+from frappe.utils.nestedset import (
+ NestedSetChildExistsError,
+ NestedSetInvalidMergeError,
+ NestedSetMultipleRootsError,
+ NestedSetRecursionError,
+ get_ancestors_of,
+ rebuild_tree,
+)
test_records = frappe.get_test_records('Item Group')
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index c1f9433b411..005cfec769a 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -2,15 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-
-from frappe.utils import cstr, cint
-from frappe import msgprint, throw, _
-
+from frappe import _, msgprint, throw
+from frappe.core.doctype.doctype.doctype import validate_series
from frappe.model.document import Document
from frappe.model.naming import parse_naming_series
from frappe.permissions import get_doctypes_with_read
-from frappe.core.doctype.doctype.doctype import validate_series
+from frappe.utils import cint, cstr
+
class NamingSeriesNotSetError(frappe.ValidationError): pass
@@ -79,7 +79,8 @@ class NamingSeries(Document):
options = self.scrub_options_list(ol)
# validate names
- for i in options: self.validate_series_name(i)
+ for i in options:
+ self.validate_series_name(i)
if options and self.user_must_always_select:
options = [''] + options
@@ -138,7 +139,7 @@ class NamingSeries(Document):
def validate_series_name(self, n):
import re
- if not re.match("^[\w\- /.#{}]*$", n, re.UNICODE):
+ if not re.match(r"^[\w\- \/.#{}]+$", n, re.UNICODE):
throw(_('Special Characters except "-", "#", ".", "/", "{" and "}" not allowed in naming series'))
@frappe.whitelist()
diff --git a/erpnext/setup/doctype/naming_series/test_naming_series.js b/erpnext/setup/doctype/naming_series/test_naming_series.js
deleted file mode 100644
index 22b664b2e6d..00000000000
--- a/erpnext/setup/doctype/naming_series/test_naming_series.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Naming Series", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Naming Series
- () => frappe.tests.make('Naming Series', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/party_type/party_type.py b/erpnext/setup/doctype/party_type/party_type.py
index 96e60936a4b..8424c7fe938 100644
--- a/erpnext/setup/doctype/party_type/party_type.py
+++ b/erpnext/setup/doctype/party_type/party_type.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.model.document import Document
+
class PartyType(Document):
pass
diff --git a/erpnext/setup/doctype/party_type/test_party_type.js b/erpnext/setup/doctype/party_type/test_party_type.js
deleted file mode 100644
index c97dbc58c80..00000000000
--- a/erpnext/setup/doctype/party_type/test_party_type.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Party Type", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Party Type
- () => frappe.tests.make('Party Type', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/party_type/test_party_type.py b/erpnext/setup/doctype/party_type/test_party_type.py
index 079fe2fe3b7..e5f2908eb46 100644
--- a/erpnext/setup/doctype/party_type/test_party_type.py
+++ b/erpnext/setup/doctype/party_type/test_party_type.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('Party Type')
diff --git a/erpnext/setup/doctype/print_heading/print_heading.py b/erpnext/setup/doctype/print_heading/print_heading.py
index 3d5cd2d6f9e..cf25638608b 100644
--- a/erpnext/setup/doctype/print_heading/print_heading.py
+++ b/erpnext/setup/doctype/print_heading/print_heading.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class PrintHeading(Document):
pass
diff --git a/erpnext/setup/doctype/print_heading/test_print_heading.py b/erpnext/setup/doctype/print_heading/test_print_heading.py
index b2be2e375e4..06f801a654e 100644
--- a/erpnext/setup/doctype/print_heading/test_print_heading.py
+++ b/erpnext/setup/doctype/print_heading/test_print_heading.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Print Heading')
diff --git a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
index 42c5a5a54fb..9131cc334a7 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/quotation_lost_reason.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class QuotationLostReason(Document):
pass
diff --git a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
index f6b30b649b5..ab8d61f1ebe 100644
--- a/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
+++ b/erpnext/setup/doctype/quotation_lost_reason/test_quotation_lost_reason.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Quotation Lost Reason')
diff --git a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
index 7bb8d02670e..434f24ea925 100644
--- a/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
+++ b/erpnext/setup/doctype/quotation_lost_reason_detail/quotation_lost_reason_detail.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class QuotationLostReasonDetail(Document):
pass
diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.py b/erpnext/setup/doctype/sales_partner/sales_partner.py
index 675f9ca560b..6c741a8fb44 100644
--- a/erpnext/setup/doctype/sales_partner/sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/sales_partner.py
@@ -2,10 +2,12 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
+from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.utils import cstr, filter_strip_join
from frappe.website.website_generator import WebsiteGenerator
-from frappe.contacts.address_and_contact import load_address_and_contact
+
class SalesPartner(WebsiteGenerator):
website = frappe._dict(
diff --git a/erpnext/setup/doctype/sales_partner/test_sales_partner.py b/erpnext/setup/doctype/sales_partner/test_sales_partner.py
index 4548a4e19b5..6ece2390405 100644
--- a/erpnext/setup/doctype/sales_partner/test_sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/test_sales_partner.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Sales Partner')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/sales_person/sales_person.py b/erpnext/setup/doctype/sales_person/sales_person.py
index 19c2e5b9543..c7cad6bb998 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.py
+++ b/erpnext/setup/doctype/sales_person/sales_person.py
@@ -2,12 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
from frappe.utils.nestedset import NestedSet, get_root_of
+
from erpnext import get_default_currency
+
class SalesPerson(NestedSet):
nsm_parent_field = 'parent_sales_person'
diff --git a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
index 662008ec8db..61c1ba46d35 100644
--- a/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
+++ b/erpnext/setup/doctype/sales_person/sales_person_dashboard.py
@@ -1,6 +1,8 @@
from __future__ import unicode_literals
+
from frappe import _
+
def get_data():
return {
'heatmap': True,
diff --git a/erpnext/setup/doctype/sales_person/test_sales_person.py b/erpnext/setup/doctype/sales_person/test_sales_person.py
index 8313cb45084..497aaad74f8 100644
--- a/erpnext/setup/doctype/sales_person/test_sales_person.py
+++ b/erpnext/setup/doctype/sales_person/test_sales_person.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
test_dependencies = ["Employee"]
import frappe
+
test_records = frappe.get_test_records('Sales Person')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.py b/erpnext/setup/doctype/supplier_group/supplier_group.py
index 9d84f9097b5..0ca35257926 100644
--- a/erpnext/setup/doctype/supplier_group/supplier_group.py
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.py
@@ -3,9 +3,11 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe.utils.nestedset import NestedSet, get_root_of
+
class SupplierGroup(NestedSet):
nsm_parent_field = 'parent_supplier_group'
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.js b/erpnext/setup/doctype/supplier_group/test_supplier_group.js
deleted file mode 100644
index 976dd2cc4f3..00000000000
--- a/erpnext/setup/doctype/supplier_group/test_supplier_group.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Supplier Group", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Supplier Group
- () => frappe.tests.make('Supplier Group', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/supplier_group/test_supplier_group.py b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
index 0e3d23d6bd3..b3a636635ec 100644
--- a/erpnext/setup/doctype/supplier_group/test_supplier_group.py
+++ b/erpnext/setup/doctype/supplier_group/test_supplier_group.py
@@ -4,4 +4,5 @@
from __future__ import unicode_literals
import frappe
+
test_records = frappe.get_test_records('Supplier Group')
diff --git a/erpnext/setup/doctype/target_detail/target_detail.py b/erpnext/setup/doctype/target_detail/target_detail.py
index 633be45d20b..89cd814f2d1 100644
--- a/erpnext/setup/doctype/target_detail/target_detail.py
+++ b/erpnext/setup/doctype/target_detail/target_detail.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class TargetDetail(Document):
pass
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
index 5b00ccbdbb3..8c9059f61ef 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
@@ -2,15 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
+import json
+
import frappe
from frappe import _, throw
-import json
from frappe.model.document import Document
-from frappe.utils.jinja import validate_template
from frappe.utils import cint
-
+from frappe.utils.jinja import validate_template
from six import string_types
+
class TermsandConditions(Document):
def validate(self):
if self.terms:
diff --git a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
index 6fea78f46ae..abfa9214d64 100644
--- a/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/test_terms_and_conditions.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Terms and Conditions')
diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py
index 7eefe77495c..f61796b9bdf 100644
--- a/erpnext/setup/doctype/territory/territory.py
+++ b/erpnext/setup/doctype/territory/territory.py
@@ -2,12 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe.utils import flt
-from frappe import _
+import frappe
+from frappe import _
+from frappe.utils import flt
from frappe.utils.nestedset import NestedSet, get_root_of
+
class Territory(NestedSet):
nsm_parent_field = 'parent_territory'
diff --git a/erpnext/setup/doctype/territory/test_territory.py b/erpnext/setup/doctype/territory/test_territory.py
index efe00c5a30b..a3aa866fff3 100644
--- a/erpnext/setup/doctype/territory/test_territory.py
+++ b/erpnext/setup/doctype/territory/test_territory.py
@@ -2,8 +2,8 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('Territory')
test_ignore = ["Item Group"]
diff --git a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
index 933a8c3bed8..aa0f79b4c86 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/test_transaction_deletion_record.py
@@ -3,9 +3,11 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+import frappe
+
+
class TestTransactionDeletionRecord(unittest.TestCase):
def setUp(self):
create_company('Dunder Mifflin Paper Co')
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 8a491554801..efb038faccc 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -3,11 +3,13 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-from frappe.utils import cint
+
import frappe
-from frappe.model.document import Document
from frappe import _
from frappe.desk.notifications import clear_notifications
+from frappe.model.document import Document
+from frappe.utils import cint
+
class TransactionDeletionRecord(Document):
def validate(self):
diff --git a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
index 2176cb10deb..a113d504538 100644
--- a/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
+++ b/erpnext/setup/doctype/transaction_deletion_record_item/transaction_deletion_record_item.py
@@ -3,8 +3,10 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
# import frappe
from frappe.model.document import Document
+
class TransactionDeletionRecordItem(Document):
pass
diff --git a/erpnext/setup/doctype/uom/test_uom.py b/erpnext/setup/doctype/uom/test_uom.py
index 330d30358d9..e222c134942 100644
--- a/erpnext/setup/doctype/uom/test_uom.py
+++ b/erpnext/setup/doctype/uom/test_uom.py
@@ -2,6 +2,6 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
import frappe
+
test_records = frappe.get_test_records('UOM')
diff --git a/erpnext/setup/doctype/uom/uom.py b/erpnext/setup/doctype/uom/uom.py
index 404b84b1134..f0e97b34e25 100644
--- a/erpnext/setup/doctype/uom/uom.py
+++ b/erpnext/setup/doctype/uom/uom.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class UOM(Document):
pass
diff --git a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js
deleted file mode 100644
index afcf74ccb47..00000000000
--- a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: UOM Conversion Factor", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new UOM Conversion Factor
- () => frappe.tests.make('UOM Conversion Factor', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
index 04596efbca6..33795d6b5b2 100644
--- a/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
+++ b/erpnext/setup/doctype/uom_conversion_factor/test_uom_conversion_factor.py
@@ -5,5 +5,6 @@ from __future__ import unicode_literals
import unittest
+
class TestUOMConversionFactor(unittest.TestCase):
pass
diff --git a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
index 3566c537c6c..45342e9fee9 100644
--- a/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
+++ b/erpnext/setup/doctype/uom_conversion_factor/uom_conversion_factor.py
@@ -3,7 +3,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
from frappe.model.document import Document
+
class UOMConversionFactor(Document):
pass
diff --git a/erpnext/setup/doctype/website_item_group/website_item_group.py b/erpnext/setup/doctype/website_item_group/website_item_group.py
index e416b509b98..2f720134484 100644
--- a/erpnext/setup/doctype/website_item_group/website_item_group.py
+++ b/erpnext/setup/doctype/website_item_group/website_item_group.py
@@ -4,9 +4,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class WebsiteItemGroup(Document):
pass
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index bbee74cafb4..cdc83c14620 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -4,16 +4,18 @@
from __future__ import print_function, unicode_literals
import frappe
-from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
-from .default_success_action import get_default_success_action
from frappe import _
-from frappe.utils import cint
-from frappe.installer import update_site_config
-from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
-from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
+from frappe.installer import update_site_config
+from frappe.utils import cint
from six import iteritems
+from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
+from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+
+from .default_success_action import get_default_success_action
+
default_mail_footer = """
+{% set width_class = "expand" if not slides else "" %}
+{% set cart_settings = shopping_cart.cart_settings %}
+{% set product_info = shopping_cart.product_info %}
+{% set price_info = product_info.get('price') or {} %}
+
+
-
+{%- endmacro -%}
+
+
+{%- macro wishlist_card(item, settings) %}
+{%- set title = item.web_item_name or ''-%}
+{%- set title = title[:90] + "..." if title|len > 90 else title -%}
+
+ {% from "erpnext/templates/includes/macros.html" import wishlist_card %}
+ {% for item in items %}
+ {{ wishlist_card(item, settings) }}
+ {% endfor %}
+
+
+
+{% else %}
+
+
+
+
+
{{ _('Wishlist is empty!') }}
+
+{% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/wishlist.py b/erpnext/templates/pages/wishlist.py
new file mode 100644
index 00000000000..72ee34e157e
--- /dev/null
+++ b/erpnext/templates/pages/wishlist.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+import frappe
+
+from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import (
+ get_shopping_cart_settings,
+)
+from erpnext.e_commerce.shopping_cart.cart import _set_price_list
+from erpnext.utilities.product import get_price
+
+
+def get_context(context):
+ is_guest = frappe.session.user == "Guest"
+
+ settings = get_shopping_cart_settings()
+ items = get_wishlist_items() if not is_guest else []
+ selling_price_list = _set_price_list(settings) if not is_guest else None
+
+ items = set_stock_price_details(items, settings, selling_price_list)
+
+ context.body_class = "product-page"
+ context.items = items
+ context.settings = settings
+ context.no_cache = 1
+
+def get_stock_availability(item_code, warehouse):
+ stock_qty = frappe.utils.flt(
+ frappe.db.get_value("Bin",
+ {
+ "item_code": item_code,
+ "warehouse": warehouse
+ },
+ "actual_qty")
+ )
+ return bool(stock_qty)
+
+def get_wishlist_items():
+ if not frappe.db.exists("Wishlist", frappe.session.user):
+ return []
+
+ return frappe.db.get_all(
+ "Wishlist Item",
+ filters={
+ "parent": frappe.session.user
+ },
+ fields=[
+ "web_item_name", "item_code", "item_name",
+ "website_item", "warehouse",
+ "image", "item_group", "route"
+ ])
+
+def set_stock_price_details(items, settings, selling_price_list):
+ for item in items:
+ if settings.show_stock_availability:
+ item.available = get_stock_availability(item.item_code, item.get("warehouse"))
+
+ price_details = get_price(
+ item.item_code,
+ selling_price_list,
+ settings.default_customer_group,
+ settings.company
+ )
+
+ if price_details:
+ item.formatted_price = price_details.get('formatted_price')
+ item.formatted_mrp = price_details.get('formatted_mrp')
+ if item.formatted_mrp:
+ item.discount = price_details.get('formatted_discount_percent') or \
+ price_details.get('formatted_discount_rate')
+
+ return items
\ No newline at end of file
diff --git a/erpnext/tests/test_init.py b/erpnext/tests/test_init.py
index abc04a88084..dfba0340ceb 100644
--- a/erpnext/tests/test_init.py
+++ b/erpnext/tests/test_init.py
@@ -1,10 +1,12 @@
from __future__ import unicode_literals
+
import unittest
import frappe
-from erpnext import encode_company_abbr
from six.moves import range
+from erpnext import encode_company_abbr
+
test_records = frappe.get_test_records('Company')
class TestInit(unittest.TestCase):
diff --git a/erpnext/tests/test_notifications.py b/erpnext/tests/test_notifications.py
index 1fd90beef0f..5fd9582dea0 100644
--- a/erpnext/tests/test_notifications.py
+++ b/erpnext/tests/test_notifications.py
@@ -2,11 +2,12 @@
# MIT License. See license.txt
from __future__ import unicode_literals
-import frappe
+
import unittest
+import frappe
from frappe.desk import notifications
-from frappe.test_runner import make_test_objects
+
class TestNotifications(unittest.TestCase):
def test_get_notifications_for_targets(self):
diff --git a/erpnext/tests/test_regional.py b/erpnext/tests/test_regional.py
index 5b3f45a1af7..fe848a35558 100644
--- a/erpnext/tests/test_regional.py
+++ b/erpnext/tests/test_regional.py
@@ -1,5 +1,11 @@
from __future__ import unicode_literals
-import unittest, frappe, erpnext
+
+import unittest
+
+import frappe
+
+import erpnext
+
@erpnext.allow_regional
def test_method():
diff --git a/erpnext/tests/test_search.py b/erpnext/tests/test_search.py
index f60e5e4d983..a6619b278e1 100644
--- a/erpnext/tests/test_search.py
+++ b/erpnext/tests/test_search.py
@@ -1,8 +1,11 @@
from __future__ import unicode_literals
+
import unittest
+
import frappe
from frappe.contacts.address_and_contact import filter_dynamic_link_doctypes
+
class TestSearch(unittest.TestCase):
# Search for the word "cond", part of the word "conduire" (Lead) in french.
def test_contact_search_in_foreign_language(self):
diff --git a/erpnext/tests/test_subcontracting.py b/erpnext/tests/test_subcontracting.py
index f55137bc9cf..e45f098f65b 100644
--- a/erpnext/tests/test_subcontracting.py
+++ b/erpnext/tests/test_subcontracting.py
@@ -1,16 +1,24 @@
from __future__ import unicode_literals
-import frappe
-import unittest
+
import copy
-from frappe.utils import cint
+import unittest
from collections import defaultdict
-from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-from erpnext.stock.doctype.item.test_item import make_item
-from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+
+import frappe
+from frappe.utils import cint
+
+from erpnext.buying.doctype.purchase_order.purchase_order import (
+ get_materials_from_supplier,
+ make_purchase_invoice,
+ make_purchase_receipt,
+ make_rm_stock_entry,
+)
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
-from erpnext.buying.doctype.purchase_order.purchase_order import (make_rm_stock_entry,
- make_purchase_receipt, make_purchase_invoice, get_materials_from_supplier)
+from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+
class TestSubcontracting(unittest.TestCase):
def setUp(self):
diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py
index df715ab2027..881f286baeb 100644
--- a/erpnext/tests/test_woocommerce.py
+++ b/erpnext/tests/test_woocommerce.py
@@ -1,7 +1,15 @@
from __future__ import unicode_literals
-import unittest, frappe, requests, os, time, erpnext
+
+import os
+import time
+import unittest
+
+import frappe
+import requests
+
from erpnext.erpnext_integrations.connectors.woocommerce_connection import order
+
class TestWoocommerce(unittest.TestCase):
def setUp(self):
if not frappe.db.exists('Company', 'Woocommerce'):
diff --git a/erpnext/tests/ui_test_helpers.py b/erpnext/tests/ui_test_helpers.py
index 902fd64d686..76c7608c91f 100644
--- a/erpnext/tests/ui_test_helpers.py
+++ b/erpnext/tests/ui_test_helpers.py
@@ -1,6 +1,7 @@
import frappe
from frappe.utils import getdate
+
@frappe.whitelist()
def create_employee_records():
create_company()
diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py
index 11eb6afc1fa..2156bd51a4a 100644
--- a/erpnext/tests/utils.py
+++ b/erpnext/tests/utils.py
@@ -6,6 +6,7 @@ from contextlib import contextmanager
import frappe
+
def create_test_contact_and_address():
frappe.db.sql('delete from tabContact')
frappe.db.sql('delete from `tabContact Email`')
diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py
index 0a5aa3c49b8..ca8bc194d4c 100644
--- a/erpnext/utilities/__init__.py
+++ b/erpnext/utilities/__init__.py
@@ -1,9 +1,12 @@
## temp utility
from __future__ import print_function, unicode_literals
+
import frappe
-from erpnext.utilities.activation import get_level
from frappe.utils import cstr
+from erpnext.utilities.activation import get_level
+
+
def update_doctypes():
for d in frappe.db.sql("""select df.parent, df.fieldname
from tabDocField df, tabDocType dt where df.fieldname
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index 0f9f2f886de..c21bff0b252 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -2,11 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe, erpnext
+import frappe
from frappe import _
from six import iteritems
+import erpnext
+
+
def get_level():
activation_level = 0
sales_data = []
diff --git a/erpnext/utilities/bot.py b/erpnext/utilities/bot.py
index 485b0b3383f..9e830a20bf8 100644
--- a/erpnext/utilities/bot.py
+++ b/erpnext/utilities/bot.py
@@ -3,10 +3,10 @@
from __future__ import unicode_literals
-from frappe.utils.bot import BotParser
-
import frappe
from frappe import _
+from frappe.utils.bot import BotParser
+
class FindItemBot(BotParser):
def get_reply(self):
diff --git a/erpnext/utilities/doctype/rename_tool/rename_tool.py b/erpnext/utilities/doctype/rename_tool/rename_tool.py
index 5e3ac1a4c92..8377cecbac3 100644
--- a/erpnext/utilities/doctype/rename_tool/rename_tool.py
+++ b/erpnext/utilities/doctype/rename_tool/rename_tool.py
@@ -4,11 +4,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+import frappe
from frappe.model.document import Document
from frappe.model.rename_doc import bulk_rename
+
class RenameTool(Document):
pass
diff --git a/erpnext/utilities/doctype/sms_log/sms_log.py b/erpnext/utilities/doctype/sms_log/sms_log.py
index e634f8059ae..ce3cc46665b 100644
--- a/erpnext/utilities/doctype/sms_log/sms_log.py
+++ b/erpnext/utilities/doctype/sms_log/sms_log.py
@@ -2,9 +2,9 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
from frappe.model.document import Document
+
class SMSLog(Document):
pass
diff --git a/erpnext/utilities/doctype/sms_log/test_sms_log.py b/erpnext/utilities/doctype/sms_log/test_sms_log.py
index 65f52b40018..3baeb255790 100644
--- a/erpnext/utilities/doctype/sms_log/test_sms_log.py
+++ b/erpnext/utilities/doctype/sms_log/test_sms_log.py
@@ -3,7 +3,6 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
# test_records = frappe.get_test_records('SMS Log')
diff --git a/erpnext/utilities/doctype/video/test_video.py b/erpnext/utilities/doctype/video/test_video.py
index 33ea31c919e..530136c6f39 100644
--- a/erpnext/utilities/doctype/video/test_video.py
+++ b/erpnext/utilities/doctype/video/test_video.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestVideo(unittest.TestCase):
pass
diff --git a/erpnext/utilities/doctype/video/video.py b/erpnext/utilities/doctype/video/video.py
index c2e414eef8c..d9907cf02e2 100644
--- a/erpnext/utilities/doctype/video/video.py
+++ b/erpnext/utilities/doctype/video/video.py
@@ -3,14 +3,17 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-import frappe
+
import re
-import pytz
-from frappe.model.document import Document
-from frappe import _
from datetime import datetime
-from six import string_types
+
+import frappe
+import pytz
+from frappe import _
+from frappe.model.document import Document
from pyyoutube import Api
+from six import string_types
+
class Video(Document):
def validate(self):
diff --git a/erpnext/utilities/doctype/video_settings/test_video_settings.py b/erpnext/utilities/doctype/video_settings/test_video_settings.py
index b217afe3d84..e871435a930 100644
--- a/erpnext/utilities/doctype/video_settings/test_video_settings.py
+++ b/erpnext/utilities/doctype/video_settings/test_video_settings.py
@@ -6,5 +6,6 @@ from __future__ import unicode_literals
# import frappe
import unittest
+
class TestVideoSettings(unittest.TestCase):
pass
diff --git a/erpnext/utilities/doctype/video_settings/video_settings.py b/erpnext/utilities/doctype/video_settings/video_settings.py
index db021b473a4..72091343b4c 100644
--- a/erpnext/utilities/doctype/video_settings/video_settings.py
+++ b/erpnext/utilities/doctype/video_settings/video_settings.py
@@ -3,10 +3,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
+from apiclient.discovery import build
from frappe import _
from frappe.model.document import Document
-from apiclient.discovery import build
+
class VideoSettings(Document):
def validate(self):
diff --git a/erpnext/utilities/hierarchy_chart.py b/erpnext/utilities/hierarchy_chart.py
index 384d84194bb..0e7f81fb8ee 100644
--- a/erpnext/utilities/hierarchy_chart.py
+++ b/erpnext/utilities/hierarchy_chart.py
@@ -2,21 +2,27 @@
# MIT License. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
+
@frappe.whitelist()
-def get_all_nodes(parent, parent_name, method, company):
+def get_all_nodes(method, company):
'''Recursively gets all data from nodes'''
method = frappe.get_attr(method)
if method not in frappe.whitelisted:
frappe.throw(_('Not Permitted'), frappe.PermissionError)
- data = method(parent, company)
- result = [dict(parent=parent, parent_name=parent_name, data=data)]
+ root_nodes = method(company=company)
+ result = []
+ nodes_to_expand = []
- nodes_to_expand = [{'id': d.get('id'), 'name': d.get('name')} for d in data if d.get('expandable')]
+ for root in root_nodes:
+ data = method(root.id, company)
+ result.append(dict(parent=root.id, parent_name=root.name, data=data))
+ nodes_to_expand.extend([{'id': d.get('id'), 'name': d.get('name')} for d in data if d.get('expandable')])
while nodes_to_expand:
parent = nodes_to_expand.pop(0)
diff --git a/erpnext/utilities/product.py b/erpnext/utilities/product.py
index 70b41767d6d..ec5eb1dc859 100644
--- a/erpnext/utilities/product.py
+++ b/erpnext/utilities/product.py
@@ -4,19 +4,21 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cint, fmt_money, flt, nowdate, getdate
+from frappe.utils import cint, flt, fmt_money, getdate, nowdate
+
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item
from erpnext.stock.doctype.batch.batch import get_batch_qty
-def get_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
+
+def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
in_stock, stock_qty = 0, ''
template_item_code, is_stock_item = frappe.db.get_value("Item", item_code, ["variant_of", "is_stock_item"])
if not warehouse:
- warehouse = frappe.db.get_value("Item", item_code, item_warehouse_field)
+ warehouse = frappe.db.get_value("Website Item", {"item_code": item_code}, item_warehouse_field)
if not warehouse and template_item_code and template_item_code != item_code:
- warehouse = frappe.db.get_value("Item", template_item_code, item_warehouse_field)
+ warehouse = frappe.db.get_value("Website Item", {"item_code": template_item_code}, item_warehouse_field)
if warehouse:
stock_qty = frappe.db.sql("""
@@ -91,17 +93,27 @@ def get_price(item_code, price_list, customer_group, company, qty=1):
"for_shopping_cart": True,
"currency": frappe.db.get_value("Price List", price_list, "currency")
}))
+ price_obj = price[0]
if pricing_rule:
+ # price without any rules applied
+ mrp = price_obj.price_list_rate or 0
+
if pricing_rule.pricing_rule_for == "Discount Percentage":
- price[0].price_list_rate = flt(price[0].price_list_rate * (1.0 - (flt(pricing_rule.discount_percentage) / 100.0)))
+ price_obj.discount_percent = pricing_rule.discount_percentage
+ price_obj.formatted_discount_percent = str(flt(pricing_rule.discount_percentage, 0)) + "%"
+ price_obj.price_list_rate = flt(price_obj.price_list_rate * (1.0 - (flt(pricing_rule.discount_percentage) / 100.0)))
if pricing_rule.pricing_rule_for == "Rate":
- price[0].price_list_rate = pricing_rule.price_list_rate
+ rate_discount = flt(mrp) - flt(pricing_rule.price_list_rate)
+ if rate_discount > 0:
+ price_obj.formatted_discount_rate = fmt_money(rate_discount, currency=price_obj["currency"])
+ price_obj.price_list_rate = pricing_rule.price_list_rate or 0
- price_obj = price[0]
if price_obj:
price_obj["formatted_price"] = fmt_money(price_obj["price_list_rate"], currency=price_obj["currency"])
+ if mrp != price_obj["price_list_rate"]:
+ price_obj["formatted_mrp"] = fmt_money(mrp, currency=price_obj["currency"])
price_obj["currency_symbol"] = not cint(frappe.db.get_default("hide_currency_symbol")) \
and (frappe.db.get_value("Currency", price_obj.currency, "symbol", cache=True) or price_obj.currency) \
@@ -122,15 +134,15 @@ def get_price(item_code, price_list, customer_group, company, qty=1):
price_obj["currency"] = ""
if not price_obj["formatted_price"]:
- price_obj["formatted_price"] = ""
+ price_obj["formatted_price"], price_obj["formatted_mrp"] = "", ""
return price_obj
def get_non_stock_item_status(item_code, item_warehouse_field):
-#if item belongs to product bundle, check if bundle items are in stock
+ # if item is a product bundle, check if its bundle items are in stock
if frappe.db.exists("Product Bundle", item_code):
items = frappe.get_doc("Product Bundle", item_code).get_all_children()
- bundle_warehouse = frappe.db.get_value('Item', item_code, item_warehouse_field)
- return all(get_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock for d in items)
+ bundle_warehouse = frappe.db.get_value("Website Item", {"item_code": item_code}, item_warehouse_field)
+ return all(get_web_item_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock for d in items)
else:
return 1
diff --git a/erpnext/utilities/report/youtube_interactions/youtube_interactions.py b/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
index 29a489ddcc7..50f3b685649 100644
--- a/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
+++ b/erpnext/utilities/report/youtube_interactions/youtube_interactions.py
@@ -2,10 +2,12 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
from frappe.utils import flt
+
def execute(filters=None):
if not frappe.db.get_single_value("Video Settings", "enable_youtube_tracking") or not filters:
return [], []
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index db997263c1a..51536834367 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -2,13 +2,15 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
import frappe.share
from frappe import _
-from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_datetime, get_link_to_form, date_diff, nowdate
+from frappe.utils import cint, cstr, flt, get_time, now_datetime
+from six import string_types
+
from erpnext.controllers.status_updater import StatusUpdater
-from six import string_types
class UOMMustBeIntegerError(frappe.ValidationError): pass
diff --git a/erpnext/utilities/web_form/addresses/addresses.py b/erpnext/utilities/web_form/addresses/addresses.py
index 3fd10175fb0..4a8d3e15949 100644
--- a/erpnext/utilities/web_form/addresses/addresses.py
+++ b/erpnext/utilities/web_form/addresses/addresses.py
@@ -1,6 +1,5 @@
from __future__ import unicode_literals
-import frappe
def get_context(context):
# do your magic here
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index 7c18ecc41fe..3d5517c5f8f 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -1,120 +1,34 @@
+{% from "erpnext/templates/includes/macros.html" import attribute_filter_section, field_filter_section, discount_range_filters %}
{% extends "templates/web.html" %}
-{% block title %}{{ _('Products') }}{% endblock %}
+
+{% block title %}{{ _('All Products') }}{% endblock %}
{% block header %}
-
{{ _('Products') }}
+
{{ _('All Products') }}
{% endblock header %}
{% block page_content %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% if items %}
- {% for item in items %}
- {% include "erpnext/www/all-products/item_row.html" %}
- {% endfor %}
- {% else %}
- {% include "erpnext/www/all-products/not_found.html" %}
- {% endif %}
-
+
+
+
+
+
-
- {% if frappe.form_dict.start or frappe.form_dict.field_filters or frappe.form_dict.attribute_filters or frappe.form_dict.search %}
-
-
- {% endif %}
-